summaryrefslogtreecommitdiffstats
path: root/tools/libclang
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-05-27 15:17:06 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-05-27 15:17:06 +0000
commit53992adde3eda3ccf9da63bc7e45673f043de18f (patch)
tree3558f327a6f9ab59c5d7a06528d84e1560445247 /tools/libclang
parent7e411337c0ed226dace6e07f1420486768161308 (diff)
downloadFreeBSD-src-53992adde3eda3ccf9da63bc7e45673f043de18f.zip
FreeBSD-src-53992adde3eda3ccf9da63bc7e45673f043de18f.tar.gz
Update clang to r104832.
Diffstat (limited to 'tools/libclang')
-rw-r--r--tools/libclang/CIndex.cpp525
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp51
-rw-r--r--tools/libclang/CIndexUSRs.cpp429
-rw-r--r--tools/libclang/CMakeLists.txt1
-rw-r--r--tools/libclang/CXCursor.cpp10
-rw-r--r--tools/libclang/CXTypes.cpp249
-rw-r--r--tools/libclang/Makefile2
-rw-r--r--tools/libclang/libclang.darwin.exports9
-rw-r--r--tools/libclang/libclang.exports10
9 files changed, 1022 insertions, 264 deletions
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index f9f7351..a077589 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -44,11 +44,11 @@ using namespace clang::cxstring;
// Crash Reporting.
//===----------------------------------------------------------------------===//
-#ifdef __APPLE__
-#define USE_CRASHTRACER
+#ifdef USE_CRASHTRACER
#include "clang/Analysis/Support/SaveAndRestore.h"
// Integrate with crash reporter.
-extern "C" const char *__crashreporter_info__;
+static const char *__crashreporter_info__ = 0;
+asm(".desc ___crashreporter_info__, 0x10");
#define NUM_CRASH_STRINGS 32
static unsigned crashtracer_counter = 0;
static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 };
@@ -152,6 +152,23 @@ static RangeComparisonResult RangeCompare(SourceManager &SM,
return RangeOverlap;
}
+/// \brief Determine if a source location falls within, before, or after a
+/// a given source range.
+static RangeComparisonResult LocationCompare(SourceManager &SM,
+ SourceLocation L, SourceRange R) {
+ assert(R.isValid() && "First range is invalid?");
+ assert(L.isValid() && "Second range is invalid?");
+ if (L == R.getBegin())
+ return RangeOverlap;
+ if (L == R.getEnd())
+ return RangeAfter;
+ if (SM.isBeforeInTranslationUnit(L, R.getBegin()))
+ return RangeBefore;
+ if (SM.isBeforeInTranslationUnit(R.getEnd(), L))
+ return RangeAfter;
+ return RangeOverlap;
+}
+
/// \brief Translate a Clang source range into a CIndex source range.
///
/// Clang internally represents ranges where the end location points to the
@@ -222,6 +239,27 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
/// \param R a half-open source range retrieved from the abstract syntax tree.
RangeComparisonResult CompareRegionOfInterest(SourceRange R);
+ class SetParentRAII {
+ CXCursor &Parent;
+ Decl *&StmtParent;
+ CXCursor OldParent;
+
+ public:
+ SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
+ : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
+ {
+ Parent = NewParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+
+ ~SetParentRAII() {
+ Parent = OldParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+ };
+
public:
CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData,
unsigned MaxPCHLevel,
@@ -259,6 +297,7 @@ public:
bool VisitObjCContainerDecl(ObjCContainerDecl *D);
bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
+ bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD);
bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
bool VisitObjCImplDecl(ObjCImplDecl *D);
bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
@@ -268,6 +307,8 @@ public:
// FIXME: ObjCCompatibleAliasDecl requires aliased-class locations.
bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
bool VisitObjCClassDecl(ObjCClassDecl *D);
+ bool VisitLinkageSpecDecl(LinkageSpecDecl *D);
+ bool VisitNamespaceDecl(NamespaceDecl *D);
// Type visitors
// FIXME: QualifiedTypeLoc doesn't provide any location information
@@ -277,6 +318,7 @@ public:
bool VisitTagTypeLoc(TagTypeLoc TL);
// FIXME: TemplateTypeParmTypeLoc doesn't provide any location information
bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL);
+ bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL);
bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL);
bool VisitPointerTypeLoc(PointerTypeLoc TL);
bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL);
@@ -297,8 +339,10 @@ public:
// FIXME: LabelStmt label?
bool VisitIfStmt(IfStmt *S);
bool VisitSwitchStmt(SwitchStmt *S);
+ bool VisitCaseStmt(CaseStmt *S);
bool VisitWhileStmt(WhileStmt *S);
bool VisitForStmt(ForStmt *S);
+// bool VisitSwitchCase(SwitchCase *S);
// Expression visitors
bool VisitBlockExpr(BlockExpr *B);
@@ -417,26 +461,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
// Set the Parent field to Cursor, then back to its old value once we're
// done.
- class SetParentRAII {
- CXCursor &Parent;
- Decl *&StmtParent;
- CXCursor OldParent;
-
- public:
- SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
- : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
- {
- Parent = NewParent;
- if (clang_isDeclaration(Parent.kind))
- StmtParent = getCursorDecl(Parent);
- }
-
- ~SetParentRAII() {
- Parent = OldParent;
- if (clang_isDeclaration(Parent.kind))
- StmtParent = getCursorDecl(Parent);
- }
- } SetParent(Parent, StmtParent, Cursor);
+ SetParentRAII SetParent(Parent, StmtParent, Cursor);
if (clang_isDeclaration(Cursor.kind)) {
Decl *D = getCursorDecl(Cursor);
@@ -504,7 +529,11 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
for (DeclContext::decl_iterator
I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
- CXCursor Cursor = MakeCXCursor(*I, TU);
+ Decl *D = *I;
+ if (D->getLexicalDeclContext() != DC)
+ continue;
+
+ CXCursor Cursor = MakeCXCursor(D, TU);
if (RegionOfInterest.isValid()) {
SourceRange Range =
@@ -642,6 +671,40 @@ bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
return VisitObjCContainerDecl(PID);
}
+bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
+ // FIXME: This implements a workaround with @property declarations also being
+ // installed in the DeclContext for the @interface. Eventually this code
+ // should be removed.
+ ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(PD->getDeclContext());
+ if (!CDecl || !CDecl->IsClassExtension())
+ return false;
+
+ ObjCInterfaceDecl *ID = CDecl->getClassInterface();
+ if (!ID)
+ return false;
+
+ IdentifierInfo *PropertyId = PD->getIdentifier();
+ ObjCPropertyDecl *prevDecl =
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId);
+
+ if (!prevDecl)
+ return false;
+
+ // Visit synthesized methods since they will be skipped when visiting
+ // the @interface.
+ if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl())
+ if (MD->isSynthesized())
+ if (Visit(MakeCXCursor(MD, TU)))
+ return true;
+
+ if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl())
+ if (MD->isSynthesized())
+ if (Visit(MakeCXCursor(MD, TU)))
+ return true;
+
+ return false;
+}
+
bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// Issue callbacks for super class.
if (D->getSuperClass() &&
@@ -705,6 +768,14 @@ bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) {
return false;
}
+bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) {
+ return VisitDeclContext(D);
+}
+
+bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ return VisitDeclContext(D);
+}
+
bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
ASTContext &Context = TU->getASTContext();
@@ -780,6 +851,13 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU)))
return true;
+ return false;
+}
+
+bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc()))
+ return true;
+
for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I),
TU)))
@@ -790,19 +868,7 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
}
bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
- if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseTypeLoc()))
- return true;
-
- if (TL.hasProtocolsAsWritten()) {
- for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
- if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I),
- TL.getProtocolLoc(I),
- TU)))
- return true;
- }
- }
-
- return false;
+ return Visit(TL.getPointeeLoc());
}
bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) {
@@ -861,13 +927,60 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
bool CursorVisitor::VisitStmt(Stmt *S) {
for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end();
Child != ChildEnd; ++Child) {
- if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU)))
- return true;
+ if (Stmt *C = *Child)
+ if (Visit(MakeCXCursor(C, StmtParent, TU)))
+ return true;
}
return false;
}
+bool CursorVisitor::VisitCaseStmt(CaseStmt *S) {
+ // Specially handle CaseStmts because they can be nested, e.g.:
+ //
+ // case 1:
+ // case 2:
+ //
+ // In this case the second CaseStmt is the child of the first. Walking
+ // these recursively can blow out the stack.
+ CXCursor Cursor = MakeCXCursor(S, StmtParent, TU);
+ while (true) {
+ // Set the Parent field to Cursor, then back to its old value once we're
+ // done.
+ SetParentRAII SetParent(Parent, StmtParent, Cursor);
+
+ if (Stmt *LHS = S->getLHS())
+ if (Visit(MakeCXCursor(LHS, StmtParent, TU)))
+ return true;
+ if (Stmt *RHS = S->getRHS())
+ if (Visit(MakeCXCursor(RHS, StmtParent, TU)))
+ return true;
+ if (Stmt *SubStmt = S->getSubStmt()) {
+ if (!isa<CaseStmt>(SubStmt))
+ return Visit(MakeCXCursor(SubStmt, StmtParent, TU));
+
+ // Specially handle 'CaseStmt' so that we don't blow out the stack.
+ CaseStmt *CS = cast<CaseStmt>(SubStmt);
+ Cursor = MakeCXCursor(CS, StmtParent, TU);
+ if (RegionOfInterest.isValid()) {
+ SourceRange Range = CS->getSourceRange();
+ if (Range.isInvalid() || CompareRegionOfInterest(Range))
+ return false;
+ }
+
+ switch (Visitor(Cursor, Parent, ClientData)) {
+ case CXChildVisit_Break: return true;
+ case CXChildVisit_Continue: return false;
+ case CXChildVisit_Recurse:
+ // Perform tail-recursion manually.
+ S = CS;
+ continue;
+ }
+ }
+ return false;
+ }
+}
+
bool CursorVisitor::VisitDeclStmt(DeclStmt *S) {
for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
@@ -1089,8 +1202,6 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
RemappedFiles.size(),
/*CaptureDiagnostics=*/true));
- // FIXME: Until we have broader testing, just drop the entire AST if we
- // encountered an error.
if (NumErrors != Diags->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.
if (CXXIdx->getDisplayDiagnostics() && Unit.get()) {
@@ -1368,6 +1479,16 @@ CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
return Result;
}
+unsigned clang_isFromMainFile(CXSourceLocation loc) {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(loc.int_data);
+ if (!loc.ptr_data[0] || Loc.isInvalid())
+ return 0;
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(loc.ptr_data[0]);
+ return SM.isFromMainFile(Loc) ? 1 : 0;
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -1474,10 +1595,11 @@ static CXString getDeclSpelling(Decl *D) {
// ObjCCategoryImplDecl returns the category name.
return createCXString(CIMP->getIdentifier()->getNameStart());
- if (ND->getIdentifier())
- return createCXString(ND->getIdentifier()->getNameStart());
-
- return createCXString("");
+ llvm::SmallString<1024> S;
+ llvm::raw_svector_ostream os(S);
+ ND->printName(os);
+
+ return createCXString(os.str());
}
CXString clang_getCursorSpelling(CXCursor C) {
@@ -1615,12 +1737,18 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("attribute(ibaction)");
case CXCursor_IBOutletAttr:
return createCXString("attribute(iboutlet)");
+ case CXCursor_IBOutletCollectionAttr:
+ return createCXString("attribute(iboutletcollection)");
case CXCursor_PreprocessingDirective:
return createCXString("preprocessing directive");
case CXCursor_MacroDefinition:
return createCXString("macro definition");
case CXCursor_MacroInstantiation:
return createCXString("macro instantiation");
+ case CXCursor_Namespace:
+ return createCXString("Namespace");
+ case CXCursor_LinkageSpec:
+ return createCXString("LinkageSpec");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -1763,7 +1891,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
- if (!getCursorDecl(C))
+ if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl)
return clang_getNullLocation();
Decl *D = getCursorDecl(C);
@@ -1829,7 +1957,7 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {
return cxloc::translateSourceRange(getCursorContext(C), R);
}
- if (!getCursorDecl(C))
+ if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl)
return clang_getNullRange();
Decl *D = getCursorDecl(C);
@@ -2286,9 +2414,15 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
const char *StartPos = Buf.data() + LocInfo.second;
IdentifierInfo *II
= CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos);
- CXTok.int_data[0] = II->getTokenID() == tok::identifier?
- CXToken_Identifier
- : CXToken_Keyword;
+
+ if (II->getObjCKeywordID() != tok::objc_not_keyword) {
+ CXTok.int_data[0] = CXToken_Keyword;
+ }
+ else {
+ CXTok.int_data[0] = II->getTokenID() == tok::identifier?
+ CXToken_Identifier
+ : CXToken_Keyword;
+ }
CXTok.ptr_data = II;
} else if (Tok.is(tok::comment)) {
CXTok.int_data[0] = CXToken_Comment;
@@ -2308,62 +2442,214 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
*NumTokens = CXTokens.size();
}
+void clang_disposeTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens) {
+ free(Tokens);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Token annotation APIs.
+//===----------------------------------------------------------------------===//
+
typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData;
+static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data);
+namespace {
+class AnnotateTokensWorker {
+ AnnotateTokensData &Annotated;
+ CXToken *Tokens;
+ CXCursor *Cursors;
+ unsigned NumTokens;
+ unsigned TokIdx;
+ CursorVisitor AnnotateVis;
+ SourceManager &SrcMgr;
+
+ bool MoreTokens() const { return TokIdx < NumTokens; }
+ unsigned NextToken() const { return TokIdx; }
+ void AdvanceToken() { ++TokIdx; }
+ SourceLocation GetTokenLoc(unsigned tokI) {
+ return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]);
+ }
-enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
- CXCursor parent,
- CXClientData client_data) {
- AnnotateTokensData *Data = static_cast<AnnotateTokensData *>(client_data);
-
- // We only annotate the locations of declarations, simple
- // references, and expressions which directly reference something.
- CXCursorKind Kind = clang_getCursorKind(cursor);
- if (clang_isDeclaration(Kind) || clang_isReference(Kind)) {
- // Okay: We can annotate the location of this declaration with the
- // declaration or reference
- } else if (clang_isExpression(cursor.kind)) {
- if (Kind != CXCursor_DeclRefExpr &&
- Kind != CXCursor_MemberRefExpr &&
- Kind != CXCursor_ObjCMessageExpr)
- return CXChildVisit_Recurse;
-
- CXCursor Referenced = clang_getCursorReferenced(cursor);
- if (Referenced == cursor || Referenced == clang_getNullCursor())
- return CXChildVisit_Recurse;
-
- // Okay: we can annotate the location of this expression
- } else if (clang_isPreprocessing(cursor.kind)) {
- // We can always annotate a preprocessing directive/macro instantiation.
- } else {
- // Nothing to annotate
- return CXChildVisit_Recurse;
+public:
+ AnnotateTokensWorker(AnnotateTokensData &annotated,
+ CXToken *tokens, CXCursor *cursors, unsigned numTokens,
+ ASTUnit *CXXUnit, SourceRange RegionOfInterest)
+ : Annotated(annotated), Tokens(tokens), Cursors(cursors),
+ NumTokens(numTokens), TokIdx(0),
+ AnnotateVis(CXXUnit, AnnotateTokensVisitor, this,
+ Decl::MaxPCHLevel, RegionOfInterest),
+ SrcMgr(CXXUnit->getSourceManager()) {}
+
+ void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
+ enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
+ void AnnotateTokens(CXCursor parent);
+};
+}
+
+void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
+ // Walk the AST within the region of interest, annotating tokens
+ // along the way.
+ VisitChildren(parent);
+
+ for (unsigned I = 0 ; I < TokIdx ; ++I) {
+ AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
+ if (Pos != Annotated.end())
+ Cursors[I] = Pos->second;
}
+ // Finish up annotating any tokens left.
+ if (!MoreTokens())
+ return;
+
+ const CXCursor &C = clang_getNullCursor();
+ for (unsigned I = TokIdx ; I < NumTokens ; ++I) {
+ AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
+ Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second;
+ }
+}
+
+enum CXChildVisitResult
+AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
CXSourceLocation Loc = clang_getCursorLocation(cursor);
- (*Data)[Loc.int_data] = cursor;
- return CXChildVisit_Recurse;
+ // We can always annotate a preprocessing directive/macro instantiation.
+ if (clang_isPreprocessing(cursor.kind)) {
+ Annotated[Loc.int_data] = cursor;
+ return CXChildVisit_Recurse;
+ }
+
+ CXSourceRange cursorExtent = clang_getCursorExtent(cursor);
+ SourceRange cursorRange = cxloc::translateCXSourceRange(cursorExtent);
+
+ if (cursorRange.isInvalid())
+ return CXChildVisit_Continue;
+
+ SourceLocation L = SourceLocation::getFromRawEncoding(Loc.int_data);
+
+ // Adjust the annotated range based specific declarations.
+ const enum CXCursorKind cursorK = clang_getCursorKind(cursor);
+ if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) {
+ Decl *D = cxcursor::getCursorDecl(cursor);
+ // Don't visit synthesized ObjC methods, since they have no syntatic
+ // representation in the source.
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->isSynthesized())
+ return CXChildVisit_Continue;
+ }
+ if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) {
+ TypeLoc TL = TI->getTypeLoc();
+ SourceLocation TLoc = TL.getSourceRange().getBegin();
+ if (TLoc.isValid() &&
+ SrcMgr.isBeforeInTranslationUnit(TLoc, L))
+ cursorRange.setBegin(TLoc);
+ }
+ }
+ }
+
+ const enum CXCursorKind K = clang_getCursorKind(parent);
+ const CXCursor updateC =
+ (clang_isInvalid(K) || K == CXCursor_TranslationUnit ||
+ L.isMacroID())
+ ? clang_getNullCursor() : parent;
+
+ while (MoreTokens()) {
+ const unsigned I = NextToken();
+ SourceLocation TokLoc = GetTokenLoc(I);
+ switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
+ case RangeBefore:
+ Cursors[I] = updateC;
+ AdvanceToken();
+ continue;
+ case RangeAfter:
+ return CXChildVisit_Continue;
+ case RangeOverlap:
+ break;
+ }
+ break;
+ }
+
+ // Visit children to get their cursor information.
+ const unsigned BeforeChildren = NextToken();
+ VisitChildren(cursor);
+ const unsigned AfterChildren = NextToken();
+
+ // Adjust 'Last' to the last token within the extent of the cursor.
+ while (MoreTokens()) {
+ const unsigned I = NextToken();
+ SourceLocation TokLoc = GetTokenLoc(I);
+ switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
+ case RangeBefore:
+ assert(0 && "Infeasible");
+ case RangeAfter:
+ break;
+ case RangeOverlap:
+ Cursors[I] = updateC;
+ AdvanceToken();
+ continue;
+ }
+ break;
+ }
+ const unsigned Last = NextToken();
+
+ // Scan the tokens that are at the beginning of the cursor, but are not
+ // capture by the child cursors.
+
+ // For AST elements within macros, rely on a post-annotate pass to
+ // to correctly annotate the tokens with cursors. Otherwise we can
+ // get confusing results of having tokens that map to cursors that really
+ // are expanded by an instantiation.
+ if (L.isMacroID())
+ cursor = clang_getNullCursor();
+
+ for (unsigned I = BeforeChildren; I != AfterChildren; ++I) {
+ if (!clang_isInvalid(clang_getCursorKind(Cursors[I])))
+ break;
+ Cursors[I] = cursor;
+ }
+ // Scan the tokens that are at the end of the cursor, but are not captured
+ // but the child cursors.
+ for (unsigned I = AfterChildren; I != Last; ++I)
+ Cursors[I] = cursor;
+
+ TokIdx = Last;
+ return CXChildVisit_Continue;
}
+static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent);
+}
+
+extern "C" {
+
void clang_annotateTokens(CXTranslationUnit TU,
CXToken *Tokens, unsigned NumTokens,
CXCursor *Cursors) {
- if (NumTokens == 0)
- return;
- // Any token we don't specifically annotate will have a NULL cursor.
- for (unsigned I = 0; I != NumTokens; ++I)
- Cursors[I] = clang_getNullCursor();
+ if (NumTokens == 0 || !Tokens || !Cursors)
+ return;
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
- if (!CXXUnit || !Tokens)
+ if (!CXXUnit) {
+ // Any token we don't specifically annotate will have a NULL cursor.
+ const CXCursor &C = clang_getNullCursor();
+ for (unsigned I = 0; I != NumTokens; ++I)
+ Cursors[I] = C;
return;
+ }
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
// Determine the region of interest, which contains all of the tokens.
SourceRange RegionOfInterest;
- RegionOfInterest.setBegin(
- cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));
+ RegionOfInterest.setBegin(cxloc::translateSourceLocation(
+ clang_getTokenLocation(TU, Tokens[0])));
+
SourceLocation End
= cxloc::translateSourceLocation(clang_getTokenLocation(TU,
Tokens[NumTokens - 1]));
@@ -2373,14 +2659,14 @@ void clang_annotateTokens(CXTranslationUnit TU,
// region of interest to the corresponding cursors.
AnnotateTokensData Annotated;
- // Relex the tokens within the source range to look for preprocessing
+ // Relex the tokens within the source range to look for preprocessing
// directives.
SourceManager &SourceMgr = CXXUnit->getSourceManager();
std::pair<FileID, unsigned> BeginLocInfo
= SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
std::pair<FileID, unsigned> EndLocInfo
= SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
-
+
llvm::StringRef Buffer;
bool Invalid = false;
if (BeginLocInfo.first == EndLocInfo.first &&
@@ -2388,16 +2674,16 @@ void clang_annotateTokens(CXTranslationUnit TU,
!Invalid) {
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
CXXUnit->getASTContext().getLangOptions(),
- Buffer.begin(), Buffer.data() + BeginLocInfo.second,
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second,
Buffer.end());
Lex.SetCommentRetentionState(true);
-
- // Lex tokens in raw mode until we hit the end of the range, to avoid
+
+ // Lex tokens in raw mode until we hit the end of the range, to avoid
// entering #includes or expanding macros.
while (true) {
Token Tok;
Lex.LexFromRawLexer(Tok);
-
+
reprocess:
if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
// We have found a preprocessing directive. Gobble it up so that we
@@ -2410,51 +2696,35 @@ void clang_annotateTokens(CXTranslationUnit TU,
std::vector<SourceLocation> Locations;
do {
Locations.push_back(Tok.getLocation());
- Lex.LexFromRawLexer(Tok);
+ Lex.LexFromRawLexer(Tok);
} while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
-
+
using namespace cxcursor;
CXCursor Cursor
= MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
Locations.back()),
- CXXUnit);
+ CXXUnit);
for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
Annotated[Locations[I].getRawEncoding()] = Cursor;
}
-
+
if (Tok.isAtStartOfLine())
goto reprocess;
-
+
continue;
}
-
+
if (Tok.is(tok::eof))
break;
}
}
-
- // Annotate all of the source locations in the region of interest that map to
- // a specific cursor.
- CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit);
- CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated,
- Decl::MaxPCHLevel, RegionOfInterest);
- AnnotateVis.VisitChildren(Parent);
-
- for (unsigned I = 0; I != NumTokens; ++I) {
- // Determine whether we saw a cursor at this token's location.
- AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
- if (Pos == Annotated.end())
- continue;
-
- Cursors[I] = Pos->second;
- }
-}
-void clang_disposeTokens(CXTranslationUnit TU,
- CXToken *Tokens, unsigned NumTokens) {
- free(Tokens);
+ // Annotate all of the source locations in the region of interest that map to
+ // a specific cursor.
+ AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens,
+ CXXUnit, RegionOfInterest);
+ W.AnnotateTokens(clang_getTranslationUnitCursor(CXXUnit));
}
-
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -2540,6 +2810,21 @@ CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
}
} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// C++ AST instrospection.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+unsigned clang_CXXMethod_isStatic(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+ CXXMethodDecl *D = dyn_cast<CXXMethodDecl>(cxcursor::getCursorDecl(C));
+ return (D && D->isStatic()) ? 1 : 0;
+}
+
+} // end: extern "C"
+
//===----------------------------------------------------------------------===//
// CXString Operations.
//===----------------------------------------------------------------------===//
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index a21614c..481a375 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -37,12 +37,27 @@
using namespace clang;
using namespace clang::cxstring;
+namespace {
+ /// \brief Stored representation of a completion string.
+ ///
+ /// This is the representation behind a CXCompletionString.
+ class CXStoredCodeCompletionString : public CodeCompletionString {
+ unsigned Priority;
+
+ public:
+ CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { }
+
+ unsigned getPriority() const { return Priority; }
+ };
+}
+
extern "C" {
enum CXCompletionChunkKind
clang_getCompletionChunkKind(CXCompletionString completion_string,
unsigned chunk_number) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return CXCompletionChunk_Text;
@@ -97,7 +112,8 @@ clang_getCompletionChunkKind(CXCompletionString completion_string,
CXString clang_getCompletionChunkText(CXCompletionString completion_string,
unsigned chunk_number) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return createCXString(0);
@@ -121,9 +137,12 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string,
case CodeCompletionString::CK_SemiColon:
case CodeCompletionString::CK_Equal:
case CodeCompletionString::CK_HorizontalSpace:
- case CodeCompletionString::CK_VerticalSpace:
return createCXString((*CCStr)[chunk_number].Text, false);
+ case CodeCompletionString::CK_VerticalSpace:
+ // FIXME: Temporary hack until we figure out how to handle vertical space.
+ return createCXString(" ");
+
case CodeCompletionString::CK_Optional:
// Note: treated as an empty text block.
return createCXString("");
@@ -137,7 +156,8 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string,
CXCompletionString
clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
unsigned chunk_number) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return 0;
@@ -174,10 +194,17 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
}
unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
return CCStr? CCStr->size() : 0;
}
+unsigned clang_getCompletionPriority(CXCompletionString completion_string) {
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
+ return CCStr? CCStr->getPriority() : CCP_Unlikely;
+}
+
static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
unsigned &Value) {
if (Memory + sizeof(unsigned) > MemoryEnd)
@@ -223,7 +250,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
for (unsigned I = 0, N = NumResults; I != N; ++I)
- delete (CodeCompletionString *)Results[I].CompletionString;
+ delete (CXStoredCodeCompletionString *)Results[I].CompletionString;
delete [] Results;
delete Buffer;
@@ -373,10 +400,16 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
if (ReadUnsigned(Str, StrEnd, KindValue))
break;
- CodeCompletionString *CCStr
- = CodeCompletionString::Deserialize(Str, StrEnd);
- if (!CCStr)
+ unsigned Priority;
+ if (ReadUnsigned(Str, StrEnd, Priority))
+ break;
+
+ CXStoredCodeCompletionString *CCStr
+ = new CXStoredCodeCompletionString(Priority);
+ if (!CCStr->Deserialize(Str, StrEnd)) {
+ delete CCStr;
continue;
+ }
if (!CCStr->empty()) {
// Vend the code-completion result to the caller.
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index f3c74e8..e98fd26 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -28,12 +28,33 @@ using namespace clang::cxstring;
namespace {
class USRGenerator : public DeclVisitor<USRGenerator> {
- llvm::raw_ostream &Out;
+ llvm::SmallString<1024> Buf;
+ llvm::raw_svector_ostream Out;
bool IgnoreResults;
ASTUnit *AU;
+ bool generatedLoc;
public:
- USRGenerator(ASTUnit *au, llvm::raw_ostream &out)
- : Out(out), IgnoreResults(false), AU(au) {}
+ USRGenerator(const CXCursor *C = 0)
+ : Out(Buf),
+ IgnoreResults(false),
+ AU(C ? cxcursor::getCursorASTUnit(*C) : 0),
+ generatedLoc(false)
+ {
+ // Add the USR space prefix.
+ Out << "c:";
+ }
+
+ llvm::StringRef str() {
+ return Out.str();
+ }
+
+ USRGenerator* operator->() { return this; }
+
+ template <typename T>
+ llvm::raw_svector_ostream &operator<<(const T &x) {
+ Out << x;
+ return Out;
+ }
bool ignoreResults() const { return IgnoreResults; }
@@ -52,10 +73,14 @@ public:
void VisitTagDecl(TagDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
void VisitVarDecl(VarDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ IgnoreResults = true;
+ return;
+ }
/// Generate the string component containing the location of the
/// declaration.
- void GenLoc(const Decl *D);
+ bool GenLoc(const Decl *D);
/// String generation methods used both by the visitation methods
/// and from other clients that want to directly generate USRs. These
@@ -63,10 +88,6 @@ public:
/// of an AST element), but only the fragments concerning the AST element
/// itself.
- /// Generate a USR fragment for a named declaration. This does
- /// not include the USR component for the parent.
- void GenNamedDecl(llvm::StringRef name);
-
/// Generate a USR for an Objective-C class.
void GenObjCClass(llvm::StringRef cls);
/// Generate a USR for an Objective-C class category.
@@ -81,31 +102,12 @@ public:
void GenObjCProperty(llvm::StringRef prop);
/// Generate a USR for an Objective-C protocol.
void GenObjCProtocol(llvm::StringRef prot);
-};
-class StringUSRGenerator {
-private:
- llvm::SmallString<1024> StrBuf;
- llvm::raw_svector_ostream Out;
- USRGenerator UG;
-public:
- StringUSRGenerator(const CXCursor *C = 0)
- : Out(StrBuf), UG(C ? cxcursor::getCursorASTUnit(*C) : 0, Out) {
- // Add the USR space prefix.
- Out << "c:";
- }
-
- llvm::StringRef str() {
- return Out.str();
- }
+ void VisitType(QualType T);
- USRGenerator* operator->() { return &UG; }
-
- template <typename T>
- llvm::raw_svector_ostream &operator<<(const T &x) {
- Out << x;
- return Out;
- }
+ /// 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
@@ -114,56 +116,91 @@ public:
// Generating USRs from ASTS.
//===----------------------------------------------------------------------===//
+bool USRGenerator::EmitDeclName(const NamedDecl *D) {
+ Out.flush();
+ const unsigned startSize = Buf.size();
+ D->printName(Out);
+ Out.flush();
+ const unsigned endSize = Buf.size();
+ return startSize == endSize;
+}
+
+static bool InAnonymousNamespace(const Decl *D) {
+ if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext()))
+ return ND->isAnonymousNamespace();
+ return false;
+}
+
+static inline bool ShouldGenerateLocation(const NamedDecl *D) {
+ return D->getLinkage() != ExternalLinkage && !InAnonymousNamespace(D);
+}
+
void USRGenerator::VisitDeclContext(DeclContext *DC) {
if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
Visit(D);
}
void USRGenerator::VisitFieldDecl(FieldDecl *D) {
- const std::string &s = D->getNameAsString();
- if (s.empty()) {
+ VisitDeclContext(D->getDeclContext());
+ Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@");
+ if (EmitDeclName(D)) {
// Bit fields can be anonymous.
IgnoreResults = true;
return;
}
- VisitDeclContext(D->getDeclContext());
- Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@") << s;
}
void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
- if (D->getLinkage() != ExternalLinkage) {
- GenLoc(D);
- if (IgnoreResults)
- return;
- }
- else
- VisitDeclContext(D->getDeclContext());
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ VisitDeclContext(D->getDeclContext());
+ Out << "@F@";
+ D->printName(Out);
+
+ ASTContext &Ctx = AU->getASTContext();
+ if (!Ctx.getLangOptions().CPlusPlus || D->isExternC())
+ return;
- Out << "@F@" << D;
+ // Mangle in type information for the arguments.
+ for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
+ I != E; ++I) {
+ Out << '#';
+ if (ParmVarDecl *PD = *I)
+ VisitType(PD->getType());
+ }
+ if (D->isVariadic())
+ Out << '.';
+ Out << '#';
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (MD->isStatic())
+ Out << 'S';
+ if (unsigned quals = MD->getTypeQualifiers())
+ Out << (char)('0' + quals);
+ }
}
void USRGenerator::VisitNamedDecl(NamedDecl *D) {
VisitDeclContext(D->getDeclContext());
- const std::string &s = D->getNameAsString();
- // 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())
+ 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;
- else
- GenNamedDecl(s);
+ }
}
void USRGenerator::VisitVarDecl(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 (D->getLinkage() != ExternalLinkage) {
- GenLoc(D);
- if (IgnoreResults)
- return;
- }
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ VisitDeclContext(D->getDeclContext());
// Variables always have simple names.
llvm::StringRef s = D->getName();
@@ -175,18 +212,28 @@ void USRGenerator::VisitVarDecl(VarDecl *D) {
if (s.empty())
IgnoreResults = true;
else
- GenNamedDecl(s);
+ Out << '@' << s;
}
void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
+ if (D->isAnonymousNamespace()) {
+ Out << "@aN";
+ return;
+ }
+
VisitDeclContext(D->getDeclContext());
- Out << "@N@" << D;
+ if (!IgnoreResults)
+ Out << "@N@" << D->getName();
}
void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Visit(cast<Decl>(D->getDeclContext()));
- GenObjCMethod(DeclarationName(D->getSelector()).getAsString(),
- D->isInstanceMethod());
+ // 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 N(D->getSelector());
+ N.printName(Out);
}
void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) {
@@ -258,59 +305,56 @@ void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
}
void USRGenerator::VisitTagDecl(TagDecl *D) {
+ // Add the location of the tag decl to handle resolution across
+ // translation units.
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
D = D->getCanonicalDecl();
VisitDeclContext(D->getDeclContext());
- switch (D->getTagKind()) {
- case TagDecl::TK_struct: Out << "@S"; break;
- case TagDecl::TK_class: Out << "@C"; break;
- case TagDecl::TK_union: Out << "@U"; break;
- case TagDecl::TK_enum: Out << "@E"; break;
- }
- const std::string &s = D->getNameAsString();
- const TypedefDecl *TD = 0;
- if (s.empty()) {
- TD = D->getTypedefForAnonDecl();
- Out << (TD ? 'A' : 'a');
+ switch (D->getTagKind()) {
+ case TTK_Struct: Out << "@S"; break;
+ case TTK_Class: Out << "@C"; break;
+ case TTK_Union: Out << "@U"; break;
+ case TTK_Enum: Out << "@E"; break;
}
- // Add the location of the tag decl to handle resolution across
- // translation units.
- if (D->getLinkage() == NoLinkage) {
- Out << '@';
- GenLoc(D);
- if (IgnoreResults)
- return;
- }
+ Out << '@';
+ Out.flush();
+ assert(Buf.size() > 0);
+ const unsigned off = Buf.size() - 1;
- if (s.empty()) {
- if (TD)
+ if (EmitDeclName(D)) {
+ if (const TypedefDecl *TD = D->getTypedefForAnonDecl()) {
+ Buf[off] = 'A';
Out << '@' << TD;
+ }
+ else
+ Buf[off] = 'a';
}
- else
- Out << '@' << s;
}
void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
DeclContext *DC = D->getDeclContext();
if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
Visit(DCN);
Out << "@T@";
- if (D->getLinkage() == NoLinkage) {
- GenLoc(D);
- if (IgnoreResults)
- return;
- Out << '@';
- }
Out << D->getName();
}
-void USRGenerator::GenLoc(const Decl *D) {
+bool USRGenerator::GenLoc(const Decl *D) {
+ if (generatedLoc)
+ return IgnoreResults;
+ generatedLoc = true;
+
const SourceManager &SM = AU->getSourceManager();
SourceLocation L = D->getLocStart();
if (L.isInvalid()) {
IgnoreResults = true;
- return;
+ return true;
}
L = SM.getInstantiationLoc(L);
const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
@@ -322,21 +366,145 @@ void USRGenerator::GenLoc(const Decl *D) {
else {
// This case really isn't interesting.
IgnoreResults = true;
- return;
+ return true;
}
Out << '@'
<< SM.getLineNumber(Decomposed.first, Decomposed.second) << ':'
<< SM.getColumnNumber(Decomposed.first, Decomposed.second);
+
+ 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 = AU->getASTContext();
+
+ 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 PointerType *PT = T->getAs<PointerType>()) {
+ Out << '*';
+ T = PT->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->getResultType());
+ for (FunctionProtoType::arg_type_iterator
+ I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) {
+ VisitType(*I);
+ }
+ if (FT->isVariadic())
+ Out << '.';
+ return;
+ }
+ if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+ Out << 'B';
+ T = BT->getPointeeType();
+ continue;
+ }
+ 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::Char_U:
+ 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_S:
+ case BuiltinType::SChar:
+ c = 'C'; break;
+ case BuiltinType::WChar:
+ 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::Float:
+ c = 'f'; break;
+ case BuiltinType::Double:
+ c = 'd'; break;
+ case BuiltinType::LongDouble:
+ c = 'D'; break;
+ case BuiltinType::NullPtr:
+ c = 'n'; break;
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::UndeducedAuto:
+ 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 (const ComplexType *CT = T->getAs<ComplexType>()) {
+ Out << '<';
+ T = CT->getElementType();
+ continue;
+ }
+ if (const TagType *TT = T->getAs<TagType>()) {
+ Out << '$';
+ VisitTagDecl(TT->getDecl());
+ return;
+ }
+
+ // Unhandled type.
+ Out << ' ';
+ break;
+ } while (true);
}
//===----------------------------------------------------------------------===//
// General purpose USR generation methods.
//===----------------------------------------------------------------------===//
-void USRGenerator::GenNamedDecl(llvm::StringRef name) {
- Out << "@" << name;
-}
-
void USRGenerator::GenObjCClass(llvm::StringRef cls) {
Out << "objc(cs)" << cls;
}
@@ -346,7 +514,7 @@ void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) {
}
void USRGenerator::GenObjCIvar(llvm::StringRef ivar) {
- GenNamedDecl(ivar);
+ Out << '@' << ivar;
}
void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) {
@@ -383,6 +551,7 @@ static CXString getDeclCursorUSR(const CXCursor &C) {
// Generate USRs for all entities with external linkage.
break;
case NoLinkage:
+ case UniqueExternalLinkage:
// We allow enums, typedefs, and structs that have no linkage to
// have USRs that are anchored to the file they were defined in
// (e.g., the header). This is a little gross, but in principal
@@ -390,27 +559,27 @@ static CXString getDeclCursorUSR(const CXCursor &C) {
// are referred to across multiple translation units.
if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) ||
isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND) ||
- isa<VarDecl>(ND))
+ isa<VarDecl>(ND) || isa<NamespaceDecl>(ND))
break;
// Fall-through.
case InternalLinkage:
if (isa<FunctionDecl>(ND))
break;
- case UniqueExternalLinkage:
- return createCXString("");
}
- StringUSRGenerator SUG(&C);
- SUG->Visit(D);
+ USRGenerator UG(&C);
+ UG->Visit(D);
- if (SUG->ignoreResults())
+ if (UG->ignoreResults())
return createCXString("");
+#if 0
// For development testing.
- // assert(SUG.str().size() > 2);
+ assert(UG.str().size() > 2);
+#endif
// Return a copy of the string that must be disposed by the caller.
- return createCXString(SUG.str(), true);
+ return createCXString(UG.str(), true);
}
extern "C" {
@@ -422,56 +591,56 @@ CXString clang_getCursorUSR(CXCursor C) {
return getDeclCursorUSR(C);
if (K == CXCursor_MacroDefinition) {
- StringUSRGenerator SUG(&C);
- SUG << "macro@"
- << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
- return createCXString(SUG.str(), true);
+ USRGenerator UG(&C);
+ UG << "macro@"
+ << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
+ return createCXString(UG.str(), true);
}
return createCXString("");
}
CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
- StringUSRGenerator SUG;
- SUG << extractUSRSuffix(clang_getCString(classUSR));
- SUG->GenObjCIvar(name);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCIvar(name);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCMethod(const char *name,
unsigned isInstanceMethod,
CXString classUSR) {
- StringUSRGenerator SUG;
- SUG << extractUSRSuffix(clang_getCString(classUSR));
- SUG->GenObjCMethod(name, isInstanceMethod);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCMethod(name, isInstanceMethod);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCClass(const char *name) {
- StringUSRGenerator SUG;
- SUG->GenObjCClass(name);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG->GenObjCClass(name);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCProtocol(const char *name) {
- StringUSRGenerator SUG;
- SUG->GenObjCProtocol(name);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG->GenObjCProtocol(name);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCCategory(const char *class_name,
const char *category_name) {
- StringUSRGenerator SUG;
- SUG->GenObjCCategory(class_name, category_name);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG->GenObjCCategory(class_name, category_name);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCProperty(const char *property,
CXString classUSR) {
- StringUSRGenerator SUG;
- SUG << extractUSRSuffix(clang_getCString(classUSR));
- SUG->GenObjCProperty(property);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCProperty(property);
+ return createCXString(UG.str(), true);
}
} // end extern "C"
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index d3de94a..62c9738 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -26,6 +26,7 @@ add_clang_library(libclang
CIndexUSRs.cpp
CIndexer.cpp
CXCursor.cpp
+ CXTypes.cpp
../../include/clang-c/Index.h
)
set_target_properties(libclang PROPERTIES OUTPUT_NAME clang)
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index c8eb482..f7192dd 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -56,13 +56,14 @@ static CXCursorKind GetCursorKind(Decl *D) {
case Decl::ParmVar: return CXCursor_ParmDecl;
case Decl::Typedef: return CXCursor_TypedefDecl;
case Decl::Var: return CXCursor_VarDecl;
+ case Decl::Namespace: return CXCursor_Namespace;
default:
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
- case TagDecl::TK_struct: return CXCursor_StructDecl;
- case TagDecl::TK_class: return CXCursor_ClassDecl;
- case TagDecl::TK_union: return CXCursor_UnionDecl;
- case TagDecl::TK_enum: return CXCursor_EnumDecl;
+ case TTK_Struct: return CXCursor_StructDecl;
+ case TTK_Class: return CXCursor_ClassDecl;
+ case TTK_Union: return CXCursor_UnionDecl;
+ case TTK_Enum: return CXCursor_EnumDecl;
}
}
@@ -79,6 +80,7 @@ static CXCursorKind GetCursorKind(const Attr *A) {
default: break;
case Attr::IBActionKind: return CXCursor_IBActionAttr;
case Attr::IBOutletKind: return CXCursor_IBOutletAttr;
+ case Attr::IBOutletCollectionKind: return CXCursor_IBOutletCollectionAttr;
}
return CXCursor_UnexposedAttr;
diff --git a/tools/libclang/CXTypes.cpp b/tools/libclang/CXTypes.cpp
new file mode 100644
index 0000000..137370a
--- /dev/null
+++ b/tools/libclang/CXTypes.cpp
@@ -0,0 +1,249 @@
+//===- CXTypes.cpp - Implements 'CXTypes' aspect of libclang ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+//
+// This file implements the 'CXTypes' API hooks in the Clang-C library.
+//
+//===--------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "CXCursor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Frontend/ASTUnit.h"
+
+using namespace clang;
+
+static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
+#define BTCASE(K) case BuiltinType::K: return CXType_##K
+ switch (BT->getKind()) {
+ BTCASE(Void);
+ BTCASE(Bool);
+ BTCASE(Char_U);
+ BTCASE(UChar);
+ BTCASE(Char16);
+ BTCASE(Char32);
+ BTCASE(UShort);
+ BTCASE(UInt);
+ BTCASE(ULong);
+ BTCASE(ULongLong);
+ BTCASE(UInt128);
+ BTCASE(Char_S);
+ BTCASE(SChar);
+ BTCASE(WChar);
+ BTCASE(Short);
+ BTCASE(Int);
+ BTCASE(Long);
+ BTCASE(LongLong);
+ BTCASE(Int128);
+ BTCASE(Float);
+ BTCASE(Double);
+ BTCASE(LongDouble);
+ BTCASE(NullPtr);
+ BTCASE(Overload);
+ BTCASE(Dependent);
+ BTCASE(ObjCId);
+ BTCASE(ObjCClass);
+ BTCASE(ObjCSel);
+ default:
+ return CXType_Unexposed;
+ }
+#undef BTCASE
+}
+
+static CXTypeKind GetTypeKind(QualType T) {
+ Type *TP = T.getTypePtr();
+ if (!TP)
+ return CXType_Invalid;
+
+#define TKCASE(K) case Type::K: return CXType_##K
+ switch (TP->getTypeClass()) {
+ case Type::Builtin:
+ return GetBuiltinTypeKind(cast<BuiltinType>(TP));
+ TKCASE(Complex);
+ TKCASE(Pointer);
+ TKCASE(BlockPointer);
+ TKCASE(LValueReference);
+ TKCASE(RValueReference);
+ TKCASE(Record);
+ TKCASE(Enum);
+ TKCASE(Typedef);
+ TKCASE(ObjCInterface);
+ TKCASE(ObjCObjectPointer);
+ default:
+ return CXType_Unexposed;
+ }
+#undef TKCASE
+}
+
+static CXType MakeCXType(QualType T, ASTUnit *TU) {
+ CXTypeKind TK = GetTypeKind(T);
+ CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }};
+ return CT;
+}
+
+static inline QualType GetQualType(CXType CT) {
+ return QualType::getFromOpaquePtr(CT.data[0]);
+}
+
+static inline ASTUnit* GetASTU(CXType CT) {
+ return static_cast<ASTUnit*>(CT.data[1]);
+}
+
+extern "C" {
+
+CXType clang_getCursorType(CXCursor C) {
+ ASTUnit *AU = cxcursor::getCursorASTUnit(C);
+
+ if (clang_isExpression(C.kind)) {
+ QualType T = cxcursor::getCursorExpr(C)->getType();
+ return MakeCXType(T, AU);
+ }
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (TypeDecl *TD = dyn_cast<TypeDecl>(D))
+ return MakeCXType(QualType(TD->getTypeForDecl(), 0), AU);
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return MakeCXType(QualType(ID->getTypeForDecl(), 0), AU);
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ return MakeCXType(VD->getType(), AU);
+
+ return MakeCXType(QualType(), AU);
+ }
+
+ return MakeCXType(QualType(), AU);
+}
+
+CXType clang_getCanonicalType(CXType CT) {
+ if (CT.kind == CXType_Invalid)
+ return CT;
+
+ QualType T = GetQualType(CT);
+
+ if (T.isNull())
+ return MakeCXType(QualType(), GetASTU(CT));
+
+ ASTUnit *AU = GetASTU(CT);
+ return MakeCXType(AU->getASTContext().getCanonicalType(T), AU);
+}
+
+CXType clang_getPointeeType(CXType CT) {
+ QualType T = GetQualType(CT);
+ Type *TP = T.getTypePtr();
+
+ if (!TP)
+ return MakeCXType(QualType(), GetASTU(CT));
+
+ switch (TP->getTypeClass()) {
+ case Type::Pointer:
+ T = cast<PointerType>(TP)->getPointeeType();
+ break;
+ case Type::BlockPointer:
+ T = cast<BlockPointerType>(TP)->getPointeeType();
+ break;
+ case Type::LValueReference:
+ case Type::RValueReference:
+ T = cast<ReferenceType>(TP)->getPointeeType();
+ break;
+ case Type::ObjCObjectPointer:
+ T = cast<ObjCObjectPointerType>(TP)->getPointeeType();
+ break;
+ default:
+ T = QualType();
+ break;
+ }
+ return MakeCXType(T, GetASTU(CT));
+}
+
+CXCursor clang_getTypeDeclaration(CXType CT) {
+ QualType T = GetQualType(CT);
+ Type *TP = T.getTypePtr();
+ Decl *D = 0;
+
+ switch (TP->getTypeClass()) {
+ case Type::Typedef:
+ D = cast<TypedefType>(TP)->getDecl();
+ break;
+ case Type::ObjCObject:
+ D = cast<ObjCObjectType>(TP)->getInterface();
+ break;
+ case Type::ObjCInterface:
+ D = cast<ObjCInterfaceType>(TP)->getDecl();
+ break;
+ case Type::Record:
+ case Type::Enum:
+ D = cast<TagType>(TP)->getDecl();
+ break;
+ default:
+ break;
+ }
+
+ if (!D)
+ return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+ return cxcursor::MakeCXCursor(D, GetASTU(CT));
+}
+
+CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
+ const char *s = 0;
+#define TKIND(X) case CXType_##X: s = "" #X ""; break
+ switch (K) {
+ TKIND(Invalid);
+ TKIND(Unexposed);
+ TKIND(Void);
+ TKIND(Bool);
+ TKIND(Char_U);
+ TKIND(UChar);
+ TKIND(Char16);
+ TKIND(Char32);
+ TKIND(UShort);
+ TKIND(UInt);
+ TKIND(ULong);
+ TKIND(ULongLong);
+ TKIND(UInt128);
+ TKIND(Char_S);
+ TKIND(SChar);
+ TKIND(WChar);
+ TKIND(Short);
+ TKIND(Int);
+ TKIND(Long);
+ TKIND(LongLong);
+ TKIND(Int128);
+ TKIND(Float);
+ TKIND(Double);
+ TKIND(LongDouble);
+ TKIND(NullPtr);
+ TKIND(Overload);
+ TKIND(Dependent);
+ TKIND(ObjCId);
+ TKIND(ObjCClass);
+ TKIND(ObjCSel);
+ TKIND(Complex);
+ TKIND(Pointer);
+ TKIND(BlockPointer);
+ TKIND(LValueReference);
+ TKIND(RValueReference);
+ TKIND(Record);
+ TKIND(Enum);
+ TKIND(Typedef);
+ TKIND(ObjCInterface);
+ TKIND(ObjCObjectPointer);
+ }
+#undef TKIND
+ return cxstring::createCXString(s);
+}
+
+unsigned clang_equalTypes(CXType A, CXType B) {
+ return A.data[0] == B.data[0] && A.data[1] == B.data[1];;
+}
+
+} // end: extern "C"
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index a7877bf..ff0fa33 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -50,6 +50,6 @@ ifeq ($(HOST_OS),Darwin)
ifneq ($(DARWIN_VERS),8)
LLVMLibsOptions := $(LLVMLibsOptions) \
-no-undefined -Wl,-install_name \
- -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
+ -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)"
endif
endif
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index b361168..a9f4f07 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -1,3 +1,4 @@
+_clang_CXXMethod_isStatic
_clang_annotateTokens
_clang_codeComplete
_clang_codeCompleteGetDiagnostic
@@ -21,12 +22,15 @@ _clang_disposeTranslationUnit
_clang_enableStackTraces
_clang_equalCursors
_clang_equalLocations
+_clang_equalTypes
_clang_formatDiagnostic
_clang_getCString
+_clang_getCanonicalType
_clang_getClangVersion
_clang_getCompletionChunkCompletionString
_clang_getCompletionChunkKind
_clang_getCompletionChunkText
+_clang_getCompletionPriority
_clang_getCursor
_clang_getCursorDefinition
_clang_getCursorExtent
@@ -37,6 +41,7 @@ _clang_getCursorLinkage
_clang_getCursorLocation
_clang_getCursorReferenced
_clang_getCursorSpelling
+_clang_getCursorType
_clang_getCursorUSR
_clang_getDefinitionSpellingAndExtent
_clang_getDiagnostic
@@ -58,6 +63,7 @@ _clang_getNullLocation
_clang_getNullRange
_clang_getNumCompletionChunks
_clang_getNumDiagnostics
+_clang_getPointeeType
_clang_getRange
_clang_getRangeEnd
_clang_getRangeStart
@@ -67,9 +73,12 @@ _clang_getTokenLocation
_clang_getTokenSpelling
_clang_getTranslationUnitCursor
_clang_getTranslationUnitSpelling
+_clang_getTypeDeclaration
+_clang_getTypeKindSpelling
_clang_isCursorDefinition
_clang_isDeclaration
_clang_isExpression
+_clang_isFromMainFile
_clang_isInvalid
_clang_isPreprocessing
_clang_isReference
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 991bb06..b09e6ac 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -1,3 +1,4 @@
+clang_CXXMethod_isStatic
clang_annotateTokens
clang_codeComplete
clang_codeCompleteGetDiagnostic
@@ -21,12 +22,15 @@ clang_disposeTranslationUnit
clang_enableStackTraces
clang_equalCursors
clang_equalLocations
+clang_equalTypes
clang_formatDiagnostic
clang_getCString
+clang_getCanonicalType
clang_getClangVersion
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
+clang_getCompletionPriority
clang_getCursor
clang_getCursorDefinition
clang_getCursorExtent
@@ -37,6 +41,7 @@ clang_getCursorLinkage
clang_getCursorLocation
clang_getCursorReferenced
clang_getCursorSpelling
+clang_getCursorType
clang_getCursorUSR
clang_getDefinitionSpellingAndExtent
clang_getDiagnostic
@@ -58,6 +63,7 @@ clang_getNullLocation
clang_getNullRange
clang_getNumCompletionChunks
clang_getNumDiagnostics
+clang_getPointeeType
clang_getRange
clang_getRangeEnd
clang_getRangeStart
@@ -67,9 +73,12 @@ clang_getTokenLocation
clang_getTokenSpelling
clang_getTranslationUnitCursor
clang_getTranslationUnitSpelling
+clang_getTypeDeclaration
+clang_getTypeKindSpelling
clang_isCursorDefinition
clang_isDeclaration
clang_isExpression
+clang_isFromMainFile
clang_isInvalid
clang_isPreprocessing
clang_isReference
@@ -79,3 +88,4 @@ clang_isUnexposed
clang_setUseExternalASTGeneration
clang_tokenize
clang_visitChildren
+
OpenPOWER on IntegriCloud