summaryrefslogtreecommitdiffstats
path: root/tools/libclang/CIndex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/libclang/CIndex.cpp')
-rw-r--r--tools/libclang/CIndex.cpp318
1 files changed, 235 insertions, 83 deletions
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index a43c1ab..f53e5c1 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -22,13 +22,14 @@
#include "CXTranslationUnit.h"
#include "CXType.h"
#include "CursorVisitor.h"
-#include "SimpleFormatContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Index/CommentToXML.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/PreprocessingRecord.h"
@@ -42,7 +43,6 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
-#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/Signals.h"
@@ -68,8 +68,7 @@ CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *AU) {
D->StringPool = new cxstring::CXStringPool();
D->Diagnostics = 0;
D->OverridenCursorsPool = createOverridenCXCursorsPool();
- D->FormatContext = 0;
- D->FormatInMemoryUniqueId = 0;
+ D->CommentToXML = 0;
return D;
}
@@ -308,8 +307,8 @@ bool CursorVisitor::visitDeclsFromFileRegion(FileID File,
bool VisitedAtLeastOnce = false;
DeclContext *CurDC = 0;
- SmallVector<Decl *, 16>::iterator DIt = Decls.begin();
- for (SmallVector<Decl *, 16>::iterator DE = Decls.end(); DIt != DE; ++DIt) {
+ SmallVectorImpl<Decl *>::iterator DIt = Decls.begin();
+ for (SmallVectorImpl<Decl *>::iterator DE = Decls.end(); DIt != DE; ++DIt) {
Decl *D = *DIt;
if (D->getSourceRange().isInvalid())
continue;
@@ -426,6 +425,9 @@ bool CursorVisitor::visitPreprocessedEntities(InputIterator First,
continue;
PreprocessedEntity *PPE = *First;
+ if (!PPE)
+ continue;
+
if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) {
if (Visit(MakeMacroExpansionCursor(ME, TU)))
return true;
@@ -528,9 +530,10 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
const IBOutletCollectionAttr *A =
cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor));
- if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>())
- return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(),
- A->getInterfaceLoc(), TU));
+ if (const ObjCObjectType *ObjT = A->getInterface()->getAs<ObjCObjectType>())
+ return Visit(cxcursor::MakeCursorObjCClassRef(
+ ObjT->getInterface(),
+ A->getInterfaceLoc()->getTypeLoc().getLocStart(), TU));
}
// If pointing inside a macro definition, check if the token is an identifier
@@ -698,8 +701,9 @@ bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl(
return true;
// Visit the partial specialization arguments.
- const TemplateArgumentLoc *TemplateArgs = D->getTemplateArgsAsWritten();
- for (unsigned I = 0, N = D->getNumTemplateArgsAsWritten(); I != N; ++I)
+ const ASTTemplateArgumentListInfo *Info = D->getTemplateArgsAsWritten();
+ const TemplateArgumentLoc *TemplateArgs = Info->getTemplateArgs();
+ for (unsigned I = 0, N = Info->NumTemplateArgs; I != N; ++I)
if (VisitTemplateArgumentLoc(TemplateArgs[I]))
return true;
@@ -743,18 +747,9 @@ bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) {
}
/// \brief Compare two base or member initializers based on their source order.
-static int CompareCXXCtorInitializers(const void* Xp, const void *Yp) {
- CXXCtorInitializer const * const *X
- = static_cast<CXXCtorInitializer const * const *>(Xp);
- CXXCtorInitializer const * const *Y
- = static_cast<CXXCtorInitializer const * const *>(Yp);
-
- if ((*X)->getSourceOrder() < (*Y)->getSourceOrder())
- return -1;
- else if ((*X)->getSourceOrder() > (*Y)->getSourceOrder())
- return 1;
- else
- return 0;
+static int CompareCXXCtorInitializers(CXXCtorInitializer *const *X,
+ CXXCtorInitializer *const *Y) {
+ return (*X)->getSourceOrder() - (*Y)->getSourceOrder();
}
bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
@@ -1543,6 +1538,10 @@ bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) {
return false;
}
+bool CursorVisitor::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
+ return Visit(TL.getOriginalLoc());
+}
+
bool CursorVisitor::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
// Visit the template name.
@@ -1795,6 +1794,7 @@ public:
}
};
class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void> {
+ friend class OMPClauseEnqueue;
VisitorWorkList &WL;
CXCursor Parent;
public:
@@ -1846,6 +1846,8 @@ public:
void VisitPseudoObjectExpr(const PseudoObjectExpr *E);
void VisitOpaqueValueExpr(const OpaqueValueExpr *E);
void VisitLambdaExpr(const LambdaExpr *E);
+ void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
+ void VisitOMPParallelDirective(const OMPParallelDirective *D);
private:
void AddDeclarationNameInfo(const Stmt *S);
@@ -1856,6 +1858,7 @@ private:
void AddDecl(const Decl *D, bool isFirst = true);
void AddTypeLoc(TypeSourceInfo *TI);
void EnqueueChildren(const Stmt *S);
+ void EnqueueChildren(const OMPClause *S);
};
} // end anonyous namespace
@@ -1904,6 +1907,52 @@ void EnqueueVisitor::EnqueueChildren(const Stmt *S) {
VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
std::reverse(I, E);
}
+namespace {
+class OMPClauseEnqueue : public ConstOMPClauseVisitor<OMPClauseEnqueue> {
+ EnqueueVisitor *Visitor;
+ /// \brief Process clauses with list of variables.
+ template <typename T>
+ void VisitOMPClauseList(T *Node);
+public:
+ OMPClauseEnqueue(EnqueueVisitor *Visitor) : Visitor(Visitor) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(const Class *C);
+#include "clang/Basic/OpenMPKinds.def"
+};
+
+void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
+
+template<typename T>
+void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
+ for (typename T::varlist_const_iterator I = Node->varlist_begin(),
+ E = Node->varlist_end();
+ I != E; ++I)
+ Visitor->AddStmt(*I);
+}
+
+void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseEnqueue::VisitOMPFirstprivateClause(
+ const OMPFirstprivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
+ VisitOMPClauseList(C);
+}
+}
+
+void EnqueueVisitor::EnqueueChildren(const OMPClause *S) {
+ unsigned size = WL.size();
+ OMPClauseEnqueue Visitor(this);
+ Visitor.Visit(S);
+ if (size == WL.size())
+ return;
+ // Now reverse the entries we just added. This will match the DFS
+ // ordering performed by the worklist.
+ VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
+ std::reverse(I, E);
+}
void EnqueueVisitor::VisitAddrLabelExpr(const AddrLabelExpr *E) {
WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent));
}
@@ -2027,7 +2076,6 @@ void EnqueueVisitor::VisitDeclStmt(const DeclStmt *S) {
}
void EnqueueVisitor::VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
AddStmt(E->getInit());
- typedef DesignatedInitExpr::Designator Designator;
for (DesignatedInitExpr::const_reverse_designators_iterator
D = E->designators_rbegin(), DEnd = E->designators_rend();
D != DEnd; ++D) {
@@ -2182,6 +2230,19 @@ void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
Visit(E->getSyntacticForm());
}
+void EnqueueVisitor::VisitOMPExecutableDirective(
+ const OMPExecutableDirective *D) {
+ EnqueueChildren(D);
+ for (ArrayRef<OMPClause *>::iterator I = D->clauses().begin(),
+ E = D->clauses().end();
+ I != E; ++I)
+ EnqueueChildren(*I);
+}
+
+void EnqueueVisitor::VisitOMPParallelDirective(const OMPParallelDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) {
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
}
@@ -2198,8 +2259,7 @@ bool CursorVisitor::IsInRegionOfInterest(CXCursor C) {
bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
while (!WL.empty()) {
// Dequeue the worklist item.
- VisitorJob LI = WL.back();
- WL.pop_back();
+ VisitorJob LI = WL.pop_back_val();
// Set the Parent field, then back to its old value once we're done.
SetParentRAII SetParent(Parent, StmtParent, LI.getParent());
@@ -2363,9 +2423,10 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
CEnd = E->explicit_capture_end();
C != CEnd; ++C) {
- if (C->capturesThis())
+ // FIXME: Lambda init-captures.
+ if (!C->capturesVariable())
continue;
-
+
if (Visit(MakeCursorVariableRef(C->getCapturedVar(),
C->getLocation(),
TU)))
@@ -2481,10 +2542,6 @@ static void fatal_error_handler(void *user_data, const std::string& reason,
extern "C" {
CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
int displayDiagnostics) {
- // Disable pretty stack trace functionality, which will otherwise be a very
- // poor citizen of the world and set up all sorts of signal handlers.
- llvm::DisablePrettyStackTrace = true;
-
// We use crash recovery to make some of our APIs more reliable, implicitly
// enable it.
llvm::CrashRecoveryContext::Enable();
@@ -2540,9 +2597,13 @@ void clang_toggleCrashRecovery(unsigned isEnabled) {
CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
const char *ast_filename) {
- if (!CIdx)
+ if (!CIdx || !ast_filename)
return 0;
+ LOG_FUNC_SECTION {
+ *Log << ast_filename;
+ }
+
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
FileSystemOptions FileSystemOpts;
@@ -2842,7 +2903,7 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
delete CTUnit->StringPool;
delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
- delete CTUnit->FormatContext;
+ delete CTUnit->CommentToXML;
delete CTUnit;
}
}
@@ -2995,15 +3056,12 @@ int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID) {
if (!file || !outID)
return 1;
-#ifdef LLVM_ON_WIN32
- return 1; // inodes not supported on windows.
-#else
FileEntry *FEnt = static_cast<FileEntry *>(file);
- outID->data[0] = FEnt->getDevice();
- outID->data[1] = FEnt->getInode();
+ const llvm::sys::fs::UniqueID &ID = FEnt->getUniqueID();
+ outID->data[0] = ID.getDevice();
+ outID->data[1] = ID.getFile();
outID->data[2] = FEnt->getModificationTime();
return 0;
-#endif
}
} // end: extern "C"
@@ -3289,6 +3347,10 @@ CXString clang_getCursorSpelling(CXCursor C) {
return cxstring::createDup(AA->getLabel());
}
+ if (C.kind == CXCursor_PackedAttr) {
+ return cxstring::createRef("packed");
+ }
+
return cxstring::createEmpty();
}
@@ -3706,6 +3768,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("attribute(annotate)");
case CXCursor_AsmLabelAttr:
return cxstring::createRef("asm label");
+ case CXCursor_PackedAttr:
+ return cxstring::createRef("attribute(packed)");
case CXCursor_PreprocessingDirective:
return cxstring::createRef("preprocessing directive");
case CXCursor_MacroDefinition:
@@ -3754,6 +3818,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("CXXAccessSpecifier");
case CXCursor_ModuleImportDecl:
return cxstring::createRef("ModuleImport");
+ case CXCursor_OMPParallelDirective:
+ return cxstring::createRef("OMPParallelDirective");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -4111,6 +4177,12 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
+ if (clang_isAttribute(C.kind)) {
+ SourceLocation L
+ = cxcursor::getCursorAttr(C)->getLocation();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
if (!clang_isDeclaration(C.kind))
return clang_getNullLocation();
@@ -4521,7 +4593,9 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
return clang_getNullCursor();
}
- case Decl::Var: {
+ case Decl::Var:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization: {
// Ask the variable if it has a definition.
if (const VarDecl *Def = cast<VarDecl>(D)->getDefinition())
return MakeCXCursor(Def, TU);
@@ -4543,6 +4617,13 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
return clang_getNullCursor();
}
+ case Decl::VarTemplate: {
+ if (VarDecl *Def =
+ cast<VarTemplateDecl>(D)->getTemplatedDecl()->getDefinition())
+ return MakeCXCursor(cast<VarDecl>(Def)->getDescribedVarTemplate(), TU);
+ return clang_getNullCursor();
+ }
+
case Decl::Using:
return MakeCursorOverloadedDeclRef(cast<UsingDecl>(D),
D->getLocation(), TU);
@@ -5171,6 +5252,11 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
HasContextSensitiveKeywords = true;
}
}
+
+ // Don't override a property annotation with its getter/setter method.
+ if (cursor.kind == CXCursor_ObjCInstanceMethodDecl &&
+ parent.kind == CXCursor_ObjCPropertyDecl)
+ return CXChildVisit_Continue;
if (clang_isPreprocessing(cursor.kind)) {
// Items in the preprocessing record are kept separate from items in
@@ -5678,8 +5764,9 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
const Decl *D = cxcursor::getCursorDecl(cursor);
if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
- switch (ND->getLinkage()) {
- case NoLinkage: return CXLinkage_NoLinkage;
+ switch (ND->getLinkageInternal()) {
+ case NoLinkage:
+ case VisibleNoLinkage: return CXLinkage_NoLinkage;
case InternalLinkage: return CXLinkage_Internal;
case UniqueExternalLinkage: return CXLinkage_UniqueExternal;
case ExternalLinkage: return CXLinkage_External;
@@ -5743,25 +5830,33 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
}
extern "C" {
+
+static CXAvailabilityKind getCursorAvailabilityForDecl(const Decl *D) {
+ if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())
+ return CXAvailability_Available;
-enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
- if (clang_isDeclaration(cursor.kind))
- if (const Decl *D = cxcursor::getCursorDecl(cursor)) {
- if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())
- return CXAvailability_Available;
-
- switch (D->getAvailability()) {
- case AR_Available:
- case AR_NotYetIntroduced:
- return CXAvailability_Available;
+ switch (D->getAvailability()) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D))
+ return getCursorAvailabilityForDecl(
+ cast<Decl>(EnumConst->getDeclContext()));
+ return CXAvailability_Available;
- case AR_Deprecated:
- return CXAvailability_Deprecated;
+ case AR_Deprecated:
+ return CXAvailability_Deprecated;
- case AR_Unavailable:
- return CXAvailability_NotAvailable;
- }
- }
+ case AR_Unavailable:
+ return CXAvailability_NotAvailable;
+ }
+
+ llvm_unreachable("Unknown availability kind!");
+}
+
+enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
+ if (clang_isDeclaration(cursor.kind))
+ if (const Decl *D = cxcursor::getCursorDecl(cursor))
+ return getCursorAvailabilityForDecl(D);
return CXAvailability_Available;
}
@@ -5785,34 +5880,20 @@ static CXVersion convertVersion(VersionTuple In) {
return Out;
}
-
-int clang_getCursorPlatformAvailability(CXCursor cursor,
- int *always_deprecated,
- CXString *deprecated_message,
- int *always_unavailable,
- CXString *unavailable_message,
- CXPlatformAvailability *availability,
- int availability_size) {
- if (always_deprecated)
- *always_deprecated = 0;
- if (deprecated_message)
- *deprecated_message = cxstring::createEmpty();
- if (always_unavailable)
- *always_unavailable = 0;
- if (unavailable_message)
- *unavailable_message = cxstring::createEmpty();
-
- if (!clang_isDeclaration(cursor.kind))
- return 0;
-
- const Decl *D = cxcursor::getCursorDecl(cursor);
- if (!D)
- return 0;
-
+
+static int getCursorPlatformAvailabilityForDecl(const Decl *D,
+ int *always_deprecated,
+ CXString *deprecated_message,
+ int *always_unavailable,
+ CXString *unavailable_message,
+ CXPlatformAvailability *availability,
+ int availability_size) {
+ bool HadAvailAttr = false;
int N = 0;
for (Decl::attr_iterator A = D->attr_begin(), AEnd = D->attr_end(); A != AEnd;
++A) {
if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) {
+ HadAvailAttr = true;
if (always_deprecated)
*always_deprecated = 1;
if (deprecated_message)
@@ -5821,6 +5902,7 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
}
if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) {
+ HadAvailAttr = true;
if (always_unavailable)
*always_unavailable = 1;
if (unavailable_message) {
@@ -5830,6 +5912,7 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
}
if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(*A)) {
+ HadAvailAttr = true;
if (N < availability_size) {
availability[N].Platform
= cxstring::createDup(Avail->getPlatform()->getName());
@@ -5842,9 +5925,51 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
++N;
}
}
+
+ if (!HadAvailAttr)
+ if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D))
+ return getCursorPlatformAvailabilityForDecl(
+ cast<Decl>(EnumConst->getDeclContext()),
+ always_deprecated,
+ deprecated_message,
+ always_unavailable,
+ unavailable_message,
+ availability,
+ availability_size);
return N;
}
+
+int clang_getCursorPlatformAvailability(CXCursor cursor,
+ int *always_deprecated,
+ CXString *deprecated_message,
+ int *always_unavailable,
+ CXString *unavailable_message,
+ CXPlatformAvailability *availability,
+ int availability_size) {
+ if (always_deprecated)
+ *always_deprecated = 0;
+ if (deprecated_message)
+ *deprecated_message = cxstring::createEmpty();
+ if (always_unavailable)
+ *always_unavailable = 0;
+ if (unavailable_message)
+ *unavailable_message = cxstring::createEmpty();
+
+ if (!clang_isDeclaration(cursor.kind))
+ return 0;
+
+ const Decl *D = cxcursor::getCursorDecl(cursor);
+ if (!D)
+ return 0;
+
+ return getCursorPlatformAvailabilityForDecl(D, always_deprecated,
+ deprecated_message,
+ always_unavailable,
+ unavailable_message,
+ availability,
+ availability_size);
+}
void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
clang_disposeString(availability->Platform);
@@ -5974,6 +6099,19 @@ unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C) {
return Result;
}
+unsigned clang_Cursor_isObjCOptional(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const Decl *D = getCursorDecl(C);
+ if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
+ return PD->getPropertyImplementation() == ObjCPropertyDecl::Optional;
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->getImplementationControl() == ObjCMethodDecl::Optional;
+
+ return 0;
+}
+
unsigned clang_Cursor_isVariadic(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
@@ -6114,6 +6252,20 @@ CXFile clang_Module_getTopLevelHeader(CXTranslationUnit TU,
//===----------------------------------------------------------------------===//
extern "C" {
+unsigned clang_CXXMethod_isPureVirtual(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const CXXMethodDecl *Method = 0;
+ const Decl *D = cxcursor::getCursorDecl(C);
+ if (const FunctionTemplateDecl *FunTmpl =
+ dyn_cast_or_null<FunctionTemplateDecl>(D))
+ Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = dyn_cast_or_null<CXXMethodDecl>(D);
+ return (Method && Method->isVirtual() && Method->isPure()) ? 1 : 0;
+}
+
unsigned clang_CXXMethod_isStatic(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
OpenPOWER on IntegriCloud