diff --git a/packages/genpybind/package.py b/packages/genpybind/package.py index a50c4b57da01421f0d9bc32f8ddf3e5dcd51f7ac..b33268c5cf400f5cf0cf203c93cca07bfd3a10fe 100644 --- a/packages/genpybind/package.py +++ b/packages/genpybind/package.py @@ -42,7 +42,7 @@ class Genpybind(WafPackage): version('visions', branch='master', git='https://github.com/electronicvisions/genpybind') depends_on( - 'llvm+clang+python+visionary@5.0.0:5.999.999,7.0.0:7.999.999,9.0.0:9.999.999', + 'llvm+clang+python+visionary@5.0.0:', type=('build', 'link', 'run')) depends_on('binutils', type='build') depends_on('python@2.7:', type=('build', 'run')) diff --git a/packages/llvm/llvm11_1-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch b/packages/llvm/llvm11_1-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch new file mode 100644 index 0000000000000000000000000000000000000000..d63fd40099c6c4738f67769ab8cc148a3868c783 --- /dev/null +++ b/packages/llvm/llvm11_1-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch @@ -0,0 +1,162 @@ +From e673a5527dd2df322884eb2498736483df05957d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann@jklaehn.de> +Date: Fri, 3 Nov 2017 11:17:59 +0100 +Subject: [PATCH 2/5] [libclang] Add support for obtaining fully qualified + names of types + +This patch allows retrieving the fully qualified names of types +through libclang and clang.cindex (Python). +--- + clang/bindings/python/clang/cindex.py | 13 +++++++++++ + .../python/tests/cindex/test_cursor.py | 8 +++++++ + clang/include/clang-c/Index.h | 10 ++++++++- + clang/tools/libclang/CMakeLists.txt | 1 + + clang/tools/libclang/CXType.cpp | 22 +++++++++++++++++++ + clang/tools/libclang/libclang.exports | 1 + + 6 files changed, 54 insertions(+), 1 deletion(-) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py +index 8e5a9fe0068..c309f7017b2 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -2427,6 +2427,14 @@ class Type(Structure): + """Retrieve the spelling of this Type.""" + return conf.lib.clang_getTypeSpelling(self) + ++ @property ++ def fully_qualified_name(self): ++ """Retrieve the fully qualified name of this Type.""" ++ if not hasattr(self, '_fully_qualified_name'): ++ self._fully_qualified_name = conf.lib.clang_getFullyQualifiedTypeName(self) ++ ++ return self._fully_qualified_name ++ + def __eq__(self, other): + if type(other) != type(self): + return False +@@ -3869,6 +3877,11 @@ functionList = [ + _CXString, + _CXString.from_result), + ++ ("clang_getFullyQualifiedTypeName", ++ [Type], ++ _CXString, ++ _CXString.from_result), ++ + ("clang_hashCursor", + [Cursor], + c_uint), +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/tools/clang/bindings/python/tests/cindex/test_cursor.py +index ef875e97247..6a53c7205df 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -316,6 +316,14 @@ class TestCursor(unittest.TestCase): + underlying = typedef.underlying_typedef_type + self.assertEqual(underlying.kind, TypeKind.INT) + ++ def test_fully_qualified_type_name(): ++ source = 'namespace uiae { struct X { typedef int sometype; }; }' ++ tu = get_tu(source, lang='cpp') ++ ++ cls = get_cursor(tu, 'sometype') ++ fqn = cls.type.fully_qualified_name ++ self.assertTrue(fqn.endswith("uiae::X::sometype"), fqn) ++ + def test_semantic_parent(self): + tu = get_tu(kParentTest, 'cpp') + curs = get_cursors(tu, 'f') +diff --git a/tools/clang/include/clang-c/Index.h b/tools/clang/include/clang-c/Index.h +index 74badac740b..b0c62fe948e 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -32,7 +32,7 @@ + * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. + */ + #define CINDEX_VERSION_MAJOR 0 +-#define CINDEX_VERSION_MINOR 61 ++#define CINDEX_VERSION_MINOR 62 + + #define CINDEX_VERSION_ENCODE(major, minor) ( \ + ((major) * 10000) \ +@@ -3389,6 +3389,14 @@ CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C); + */ + CINDEX_LINKAGE CXString clang_getTypeSpelling(CXType CT); + ++/** ++ * Retrieve the fully qualified name of the underlying type. ++ * This includes full qualification of all template parameters etc. ++ * ++ * If the type is invalid, an empty string is returned. ++ */ ++CINDEX_LINKAGE CXString clang_getFullyQualifiedTypeName(CXType CT); ++ + /** + * Retrieve the underlying type of a typedef declaration. + * +diff --git a/tools/clang/tools/libclang/CMakeLists.txt b/tools/clang/tools/libclang/CMakeLists.txt +index 613ead1a36b..a583fa206d1 100644 +--- a/tools/clang/tools/libclang/CMakeLists.txt ++++ b/tools/clang/tools/libclang/CMakeLists.txt +@@ -43,6 +43,7 @@ set(LIBS + clangSema + clangSerialization + clangTooling ++ clangToolingCore + ) + + if (CLANG_ENABLE_ARCMT) +diff --git a/tools/clang/tools/libclang/CXType.cpp b/tools/clang/tools/libclang/CXType.cpp +index acecf87d0cd..afdeb467769 100644 +--- a/tools/clang/tools/libclang/CXType.cpp ++++ b/tools/clang/tools/libclang/CXType.cpp +@@ -19,6 +19,7 @@ + #include "clang/AST/DeclObjC.h" + #include "clang/AST/DeclTemplate.h" + #include "clang/AST/Expr.h" ++#include "clang/AST/QualTypeNames.h" + #include "clang/AST/Type.h" + #include "clang/Basic/AddressSpaces.h" + #include "clang/Frontend/ASTUnit.h" +@@ -302,6 +303,27 @@ CXString clang_getTypeSpelling(CXType CT) { + return cxstring::createDup(OS.str()); + } + ++CXString clang_getFullyQualifiedTypeName(CXType CT) { ++ QualType T = GetQualType(CT); ++ if (T.isNull()) ++ return cxstring::createEmpty(); ++ ++ // For builtin types (but not typedefs pointing to builtin types) return their ++ // spelling. Otherwise "bool" will be turned into "_Bool". ++ const Type *TP = T.getTypePtrOrNull(); ++ if (TP && TP->isBuiltinType() && T->getAs<TypedefType>() == nullptr) ++ return clang_getTypeSpelling(CT); ++ ++ CXTranslationUnit TU = GetTU(CT); ++ ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext(); ++ PrintingPolicy Policy(Ctx.getPrintingPolicy()); ++ Policy.SuppressScope = false; ++ Policy.AnonymousTagLocations = false; ++ Policy.PolishForDeclaration = true; ++ std::string name = TypeName::getFullyQualifiedName(T, Ctx, Policy, /*WithGlobalNsPrefix=*/true); ++ return cxstring::createDup(name.c_str()); ++} ++ + CXType clang_getTypedefDeclUnderlyingType(CXCursor C) { + using namespace cxcursor; + CXTranslationUnit TU = cxcursor::getCursorTU(C); +diff --git a/tools/clang/tools/libclang/libclang.exports b/tools/clang/tools/libclang/libclang.exports +index 3c76090d64f..6e860e7263e 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -241,6 +241,7 @@ clang_getFileLocation + clang_getFileName + clang_getFileTime + clang_getFileUniqueID ++clang_getFullyQualifiedTypeName + clang_getFunctionTypeCallingConv + clang_getIBOutletCollectionType + clang_getIncludedFile +-- +2.23.0 + diff --git a/packages/llvm/llvm11_1-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch b/packages/llvm/llvm11_1-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch new file mode 100644 index 0000000000000000000000000000000000000000..a91937d248ccc9b761201194278e53a39b3f186e --- /dev/null +++ b/packages/llvm/llvm11_1-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch @@ -0,0 +1,261 @@ +From 075a7a3e667fe3d923de6d7a6929e61922c8b139 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann@jklaehn.de> +Date: Fri, 3 Nov 2017 21:19:51 +0100 +Subject: [PATCH 3/5] [libclang] Add option to keep whitespace when tokenizing + +Introduces new `clang_tokenizeRange` function which accepts options to control +tokenization behavior. `clang_tokenize` is kept for backwards compatibility. +--- + clang/bindings/python/clang/cindex.py | 31 ++++++++++++++---- + .../python/tests/cindex/test_cursor.py | 9 ++++++ + clang/include/clang-c/Index.h | 32 +++++++++++++++++-- + clang/tools/libclang/CIndex.cpp | 15 +++++++-- + clang/tools/libclang/libclang.exports | 1 + + 5 files changed, 75 insertions(+), 13 deletions(-) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py +index c309f7017b2..1589acc9e7e 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -529,6 +529,13 @@ class TokenGroup(object): + + You should not instantiate this class outside of this module. + """ ++ ++ # Default tokenization mode. ++ TOKENIZE_NONE = 0 ++ ++ # Used to indicate that tokens for whitespace should be returned. ++ TOKENIZE_KEEP_WHITESPACE = 1 ++ + def __init__(self, tu, memory, count): + self._tu = tu + self._memory = memory +@@ -538,7 +545,7 @@ class TokenGroup(object): + conf.lib.clang_disposeTokens(self._tu, self._memory, self._count) + + @staticmethod +- def get_tokens(tu, extent): ++ def get_tokens(tu, extent, options=0): + """Helper method to return all tokens in an extent. + + This functionality is needed multiple places in this module. We define +@@ -547,8 +554,8 @@ class TokenGroup(object): + tokens_memory = POINTER(Token)() + tokens_count = c_uint() + +- conf.lib.clang_tokenize(tu, extent, byref(tokens_memory), +- byref(tokens_count)) ++ conf.lib.clang_tokenizeRange( ++ tu, extent, byref(tokens_memory), byref(tokens_count), options) + + count = int(tokens_count.value) + +@@ -1852,13 +1859,16 @@ class Cursor(Structure): + for descendant in child.walk_preorder(): + yield descendant + +- def get_tokens(self): ++ def get_tokens(self, options=0): + """Obtain Token instances formulating that compose this Cursor. + + This is a generator for Token instances. It returns all tokens which + occupy the extent this cursor occupies. ++ ++ options is a bitwise or of TokenGroup.TOKENIZE_XXX flags which will ++ control tokenization behavior. + """ +- return TokenGroup.get_tokens(self._tu, self.extent) ++ return TokenGroup.get_tokens(self._tu, self.extent, options) + + def get_field_offsetof(self): + """Returns the offsetof the FIELD_DECL pointed by this Cursor.""" +@@ -3080,18 +3090,21 @@ class TranslationUnit(ClangObject): + return CodeCompletionResults(ptr) + return None + +- def get_tokens(self, locations=None, extent=None): ++ def get_tokens(self, locations=None, extent=None, options=0): + """Obtain tokens in this translation unit. + + This is a generator for Token instances. The caller specifies a range + of source code to obtain tokens for. The range can be specified as a + 2-tuple of SourceLocation or as a SourceRange. If both are defined, + behavior is undefined. ++ ++ options is a bitwise or of TokenGroup.TOKENIZE_XXX flags which will ++ control tokenization behavior. + """ + if locations is not None: + extent = SourceRange(start=locations[0], end=locations[1]) + +- return TokenGroup.get_tokens(self, extent) ++ return TokenGroup.get_tokens(self, extent, options) + + class File(ClangObject): + """ +@@ -3969,6 +3982,10 @@ functionList = [ + ("clang_tokenize", + [TranslationUnit, SourceRange, POINTER(POINTER(Token)), POINTER(c_uint)]), + ++ ("clang_tokenizeRange", ++ [TranslationUnit, SourceRange, POINTER(POINTER(Token)), POINTER(c_uint), ++ c_uint]), ++ + ("clang_visitChildren", + [Cursor, callbacks['cursor_visit'], py_object], + c_uint), +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py +index 6a53c7205df..0965c1f4ae1 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -10,6 +10,7 @@ import unittest + from clang.cindex import AvailabilityKind + from clang.cindex import CursorKind + from clang.cindex import TemplateArgumentKind ++from clang.cindex import TokenGroup + from clang.cindex import TranslationUnit + from clang.cindex import TypeKind + from .util import get_cursor +@@ -488,6 +489,14 @@ class TestCursor(unittest.TestCase): + self.assertEqual(tokens[0].spelling, 'int') + self.assertEqual(tokens[1].spelling, 'foo') + ++ def test_get_tokens_with_whitespace(): ++ source = 'class C { void f(); }\nvoid C::f() { }' ++ tu = get_tu(source) ++ ++ tokens = list(tu.cursor.get_tokens(TokenGroup.TOKENIZE_KEEP_WHITESPACE)) ++ self.assertEqual(''.join(t.spelling for t in tokens), source) ++ self.assertEqual(len(tokens), 27, [t.spelling for t in tokens]) ++ + def test_get_token_cursor(self): + """Ensure we can map tokens to cursors.""" + tu = get_tu('class A {}; int foo(A var = A());', lang='cpp') +diff --git a/tools/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h +index b0c62fe948e..84ed03b8920 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -32,7 +32,7 @@ + * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. + */ + #define CINDEX_VERSION_MAJOR 0 +-#define CINDEX_VERSION_MINOR 62 ++#define CINDEX_VERSION_MINOR 63 + + #define CINDEX_VERSION_ENCODE(major, minor) ( \ + ((major) * 10000) \ +@@ -4969,6 +4969,28 @@ CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit, + */ + CINDEX_LINKAGE CXSourceRange clang_getTokenExtent(CXTranslationUnit, CXToken); + ++typedef enum { ++ /** ++ * \brief Used to indicate that no special tokenization options are needed. ++ */ ++ CXTokenize_None = 0x0, ++ ++ /** ++ * \brief Used to indicate that tokens for whitespace should be returned. ++ */ ++ CXTokenize_KeepWhitespace = 0x1 ++} CXTokenize_Flags; ++ ++/** ++ * \brief Tokenize the source code described by the given range into raw ++ * lexical tokens. ++ * ++ * \see clang_tokenizeRange ++ * ++ */ ++CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, ++ CXToken **Tokens, unsigned *NumTokens); ++ + /** + * Tokenize the source code described by the given range into raw + * lexical tokens. +@@ -4985,9 +5007,13 @@ CINDEX_LINKAGE CXSourceRange clang_getTokenExtent(CXTranslationUnit, CXToken); + * \param NumTokens will be set to the number of tokens in the \c *Tokens + * array. + * ++ * \param options A bitmask of options that affects tokenization. This should be ++ * a bitwise OR of the CXTokenize_XXX flags. ++ * + */ +-CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, +- CXToken **Tokens, unsigned *NumTokens); ++CINDEX_LINKAGE void clang_tokenizeRange(CXTranslationUnit TU, ++ CXSourceRange Range, CXToken **Tokens, ++ unsigned *NumTokens, unsigned options); + + /** + * Annotate the given set of tokens by providing cursors for each token +diff --git a/tools/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp +index 1dc961f58a2..3a283e76ed8 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -6670,7 +6670,7 @@ CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) { + } + + static void getTokens(ASTUnit *CXXUnit, SourceRange Range, +- SmallVectorImpl<CXToken> &CXTokens) { ++ SmallVectorImpl<CXToken> &CXTokens, unsigned options) { + SourceManager &SourceMgr = CXXUnit->getSourceManager(); + std::pair<FileID, unsigned> BeginLocInfo + = SourceMgr.getDecomposedSpellingLoc(Range.getBegin()); +@@ -6692,6 +6692,9 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range, + CXXUnit->getASTContext().getLangOpts(), + Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end()); + Lex.SetCommentRetentionState(true); ++ if (options & CXTokenize_KeepWhitespace) { ++ Lex.SetKeepWhitespaceMode(true); ++ } + + // Lex tokens until we hit the end of the range. + const char *EffectiveBufferEnd = Buffer.data() + EndLocInfo.second; +@@ -6765,7 +6768,7 @@ CXToken *clang_getToken(CXTranslationUnit TU, CXSourceLocation Location) { + SourceLocation End = SM.getComposedLoc(DecomposedEnd.first, DecomposedEnd.second); + + SmallVector<CXToken, 32> CXTokens; +- getTokens(CXXUnit, SourceRange(Begin, End), CXTokens); ++ getTokens(CXXUnit, SourceRange(Begin, End), CXTokens, CXTokenize_None); + + if (CXTokens.empty()) + return NULL; +@@ -6913,6 +6913,12 @@ CXToken *clang_getToken(CXTranslationUni + + void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, CXToken **Tokens, + unsigned *NumTokens) { ++ return clang_tokenizeRange(TU, Range, Tokens, NumTokens, CXTokenize_None); ++} ++ ++void clang_tokenizeRange(CXTranslationUnit TU, CXSourceRange Range, ++ CXToken **Tokens, unsigned *NumTokens, ++ unsigned options) { + LOG_FUNC_SECTION { *Log << TU << ' ' << Range; } + + if (Tokens) +@@ -6804,7 +6813,7 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, + return; + + SmallVector<CXToken, 32> CXTokens; +- getTokens(CXXUnit, R, CXTokens); ++ getTokens(CXXUnit, R, CXTokens, options); + + if (CXTokens.empty()) + return; +diff --git a/tools/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports +index 6e860e7263e..6af6c0ca3e8 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -338,6 +338,7 @@ clang_suspendTranslationUnit + clang_sortCodeCompletionResults + clang_toggleCrashRecovery + clang_tokenize ++clang_tokenizeRange + clang_CompilationDatabase_fromDirectory + clang_CompilationDatabase_dispose + clang_CompilationDatabase_getCompileCommands +-- +2.23.0 + diff --git a/packages/llvm/llvm11_1-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch b/packages/llvm/llvm11_1-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch new file mode 100644 index 0000000000000000000000000000000000000000..f7ce6f2cd5e79c43215fba244f599a5cde6fcbf7 --- /dev/null +++ b/packages/llvm/llvm11_1-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch @@ -0,0 +1,437 @@ +From d10d66b8e762c1dd1329d5920f9ef952cf4f6940 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Mon, 17 Jul 2017 12:25:49 +0200 +Subject: [PATCH 4/5] [libclang] WIP: Allow visiting of implicit declarations + and template instantiations + +--- + clang/bindings/python/clang/cindex.py | 45 +++++-- + .../python/tests/cindex/test_cursor.py | 33 ++++++ + clang/include/clang-c/Index.h | 33 +++++- + clang/tools/libclang/CIndex.cpp | 112 ++++++++++++++++-- + clang/tools/libclang/CursorVisitor.h | 12 +- + clang/tools/libclang/libclang.exports | 2 + + 6 files changed, 220 insertions(+), 17 deletions(-) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py +index 1589acc9e7e..b023be6cdc8 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -1426,6 +1426,15 @@ class Cursor(Structure): + """ + _fields_ = [("_kind_id", c_int), ("xdata", c_int), ("data", c_void_p * 3)] + ++ # Default behavior. ++ GET_CHILDREN_NONE = 0 ++ ++ # Used to indicate that implicit cursors should be visited. ++ GET_CHILDREN_WITH_IMPLICIT = 1 ++ ++ # Used to indicate that template instantiations should be visited. ++ GET_CHILDREN_WITH_TEMPLATE_INSTANTIATIONS = 2 ++ + @staticmethod + def from_location(tu, location): + # We store a reference to the TU in the instance so the TU won't get +@@ -1515,6 +1524,10 @@ class Cursor(Structure): + """ + return conf.lib.clang_EnumDecl_isScoped(self) + ++ def is_implicit(self): ++ """Test whether the cursor refers to an implicit declaration.""" ++ return conf.lib.clang_isImplicit(self) ++ + def get_definition(self): + """ + If the cursor is a reference to a declaration or a declaration of +@@ -1831,8 +1844,12 @@ class Cursor(Structure): + """Returns the value of the indicated arg as an unsigned 64b integer.""" + return conf.lib.clang_Cursor_getTemplateArgumentUnsignedValue(self, num) + +- def get_children(self): +- """Return an iterator for accessing the children of this cursor.""" ++ def get_children(self, with_implicit=False, with_template_instantiations=False): ++ """Return an iterator for accessing the children of this cursor. ++ ++ By default, cursors representing implicit declarations or template instantiations ++ will be skipped. ++ """ + + # FIXME: Expose iteration from CIndex, PR6125. + def visitor(child, parent, children): +@@ -1845,18 +1862,24 @@ class Cursor(Structure): + children.append(child) + return 1 # continue + children = [] +- conf.lib.clang_visitChildren(self, callbacks['cursor_visit'](visitor), +- children) ++ dispatch = conf.lib.clang_visitChildren ++ options = Cursor.GET_CHILDREN_NONE ++ if with_implicit: ++ options |= Cursor.GET_CHILDREN_WITH_IMPLICIT ++ if with_template_instantiations: ++ options |= Cursor.GET_CHILDREN_WITH_TEMPLATE_INSTANTIATIONS ++ conf.lib.clang_visitChildrenWithOptions( ++ self, callbacks['cursor_visit'](visitor), children, options) + return iter(children) + +- def walk_preorder(self): ++ def walk_preorder(self, **kwargs): + """Depth-first preorder walk over the cursor and its descendants. + + Yields cursors. + """ + yield self +- for child in self.get_children(): +- for descendant in child.walk_preorder(): ++ for child in self.get_children(**kwargs): ++ for descendant in child.walk_preorder(**kwargs): + yield descendant + + def get_tokens(self, options=0): +@@ -3927,6 +3950,10 @@ functionList = [ + [Type], + bool), + ++ ("clang_isImplicit", ++ [Cursor], ++ bool), ++ + ("clang_isInvalid", + [CursorKind], + bool), +@@ -3990,6 +4017,10 @@ functionList = [ + [Cursor, callbacks['cursor_visit'], py_object], + c_uint), + ++ ("clang_visitChildrenWithOptions", ++ [Cursor, callbacks['cursor_visit'], py_object, c_uint], ++ c_uint), ++ + ("clang_Cursor_getNumArguments", + [Cursor], + c_int), +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py +index 0965c1f4ae1..d061f37c25c 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -94,6 +94,39 @@ class TestCursor(unittest.TestCase): + self.assertEqual(tu_nodes[2].displayname, 'f0(int, int)') + self.assertEqual(tu_nodes[2].is_definition(), True) + ++ def test_get_children_with_implicit(): ++ tu = get_tu('struct X {}; X x;', lang='cpp') ++ cursor = get_cursor(tu, 'X') ++ ++ children = list(cursor.get_children()) ++ self.assertEqual(len(children), 0, [(c.kind, c.spelling) for c in children]) ++ ++ children = list(cursor.get_children(with_implicit=True)) ++ self.assertNotEqual(len(children), 0) ++ for child in children: ++ self.assertTrue(child.is_implicit()) ++ self.assertEqual(child.spelling, "X") ++ self.assertIn(child.kind, [CursorKind.CONSTRUCTOR, CursorKind.STRUCT_DECL]) ++ ++ def test_get_children_with_template_instantiations(): ++ tu = get_tu( ++ 'template <typename T> T frobnicate(T val);' ++ 'extern template int frobnicate<int>(int);', ++ lang='cpp') ++ cursor = get_cursor(tu, 'frobnicate') ++ self.assertEqual(cursor.kind, CursorKind.FUNCTION_TEMPLATE) ++ ++ for child in cursor.get_children(): ++ # should not return an instantiation: ++ self.assertNotEqual(child.kind, CursorKind.FUNCTION_DECL) ++ ++ for child in cursor.get_children(with_template_instantiations=True): ++ if child.kind == CursorKind.FUNCTION_DECL: ++ self.assertEqual(child.spelling, 'frobnicate') ++ break ++ else: ++ self.fail("Couldn't find template instantiation") ++ + def test_references(self): + """Ensure that references to TranslationUnit are kept.""" + tu = get_tu('int x;') +diff --git a/tools/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h +index 84ed03b8920..57acbcba143 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -32,7 +32,7 @@ + * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. + */ + #define CINDEX_VERSION_MAJOR 0 +-#define CINDEX_VERSION_MINOR 63 ++#define CINDEX_VERSION_MINOR 64 + + #define CINDEX_VERSION_ENCODE(major, minor) ( \ + ((major) * 10000) \ +@@ -2775,6 +2775,11 @@ CINDEX_LINKAGE unsigned clang_isPreprocessing(enum CXCursorKind); + */ + CINDEX_LINKAGE unsigned clang_isUnexposed(enum CXCursorKind); + ++/*** ++ * \brief Determine whether the given cursor represents an implicit declaration. ++ */ ++CINDEX_LINKAGE unsigned clang_isImplicit(CXCursor); ++ + /** + * Describe the linkage of the entity referred to by a cursor. + */ +@@ -4199,6 +4204,32 @@ CINDEX_LINKAGE unsigned clang_visitChildrenWithBlock(CXCursor parent, + # endif + #endif + ++typedef enum { ++ /** ++ * \brief Default behavior. ++ */ ++ CXVisitChildren_None = 0x0, ++ ++ /** ++ * \brief Used to indicate that implicit cursors should be visited. ++ */ ++ CXVisitChildren_WithImplicit = 0x1, ++ ++ /** ++ * \brief Used to indicate that template instantiations should be visited. ++ */ ++ CXVisitChildren_WithTemplateInstantiations = 0x2 ++} CXVisitChildren_Flags; ++ ++/** ++ * \brief Visits the children of a cursor, allowing to pass extra options. ++ * Behaves identically to clang_visitChildren() in all other respects. ++ */ ++CINDEX_LINKAGE unsigned clang_visitChildrenWithOptions(CXCursor parent, ++ CXCursorVisitor visitor, ++ CXClientData client_data, ++ unsigned options); ++ + /** + * @} + */ +diff --git a/tools/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp +index 3a283e76ed8..7ee6b704647 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -196,9 +196,10 @@ bool CursorVisitor::Visit(CXCursor Curso + return true; // abort. + } + +- // Ignore implicit declarations, unless it's an objc method because +- // currently we should report implicit methods for properties when indexing. +- if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) ++ // Unless instructed otherwise we ignore implicit declarations. ++ // ObjC methods are currently visited in any case, because implicit methods ++ // for properties should be reported when indexing. ++ if (!VisitImplicitDeclarations && D->isImplicit() && !isa<ObjCMethodDecl>(D)) + return false; + } + +@@ -706,10 +706,13 @@ bool CursorVisitor::VisitTagDecl(TagDecl + + bool CursorVisitor::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { +- bool ShouldVisitBody = false; ++ bool ShouldVisitBody = VisitTemplateInstantiations; + switch (D->getSpecializationKind()) { +- case TSK_Undeclared: + case TSK_ImplicitInstantiation: ++ if (VisitTemplateInstantiations && VisitImplicitDeclarations) { ++ break; ++ } ++ case TSK_Undeclared: + // Nothing to visit + return false; + +@@ -715,6 +719,7 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl( + break; + + case TSK_ExplicitSpecialization: ++ // Always visit body of explicit specializations + ShouldVisitBody = true; + break; + } +@@ -938,7 +941,31 @@ bool CursorVisitor::VisitFunctionTemplat + return true; + + auto *FD = D->getTemplatedDecl(); +- return VisitAttributes(FD) || VisitFunctionDecl(FD); ++ if (VisitAttributes(FD) || VisitFunctionDecl(FD)) ++ return true; ++ ++ if (VisitTemplateInstantiations && D == D->getCanonicalDecl()) { ++ for (auto *FD : D->specializations()) { ++ for (auto *RD : FD->redecls()) { ++ switch (RD->getTemplateSpecializationKind()) { ++ case TSK_Undeclared: ++ case TSK_ImplicitInstantiation: ++ case TSK_ExplicitInstantiationDeclaration: ++ case TSK_ExplicitInstantiationDefinition: { ++ const Optional<bool> V = handleDeclForVisitation(RD); ++ if (!V.hasValue()) ++ continue; ++ return V.getValue(); ++ } ++ ++ case TSK_ExplicitSpecialization: ++ break; ++ } ++ } ++ } ++ } ++ ++ return false; + } + + bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { +@@ -949,6 +976,40 @@ bool CursorVisitor::VisitClassTemplateDe + + auto *CD = D->getTemplatedDecl(); + return VisitAttributes(CD) || VisitCXXRecordDecl(CD); ++ if (VisitAttributes(CD) || VisitCXXRecordDecl(CD)) ++ return true; ++ ++ if (VisitTemplateInstantiations && D == D->getCanonicalDecl()) { ++ for (auto *SD : D->specializations()) { ++ for (auto *RD : SD->redecls()) { ++ // We don't want to visit injected-class-names in this traversal. ++ if (cast<CXXRecordDecl>(RD)->isInjectedClassName()) ++ continue; ++ ++ switch ( ++ cast<ClassTemplateSpecializationDecl>(RD)->getSpecializationKind()) { ++ // Visit the implicit instantiations with the requested pattern. ++ case TSK_Undeclared: ++ case TSK_ImplicitInstantiation: { ++ const Optional<bool> V = handleDeclForVisitation(RD); ++ if (!V.hasValue()) ++ continue; ++ return V.getValue(); ++ } ++ ++ // We don't need to do anything on an explicit instantiation ++ // or explicit specialization because there will be an explicit ++ // node for it elsewhere. ++ case TSK_ExplicitInstantiationDeclaration: ++ case TSK_ExplicitInstantiationDefinition: ++ case TSK_ExplicitSpecialization: ++ break; ++ } ++ } ++ } ++ } ++ ++ return false; + } + + bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { +@@ -4426,6 +4488,24 @@ unsigned clang_visitChildrenWithBlock(CXCursor parent, + return clang_visitChildren(parent, visitWithBlock, block); + } + ++unsigned clang_visitChildrenWithOptions(CXCursor parent, ++ CXCursorVisitor visitor, ++ CXClientData client_data, ++ unsigned options) { ++ CursorVisitor CursorVis( ++ getCursorTU(parent), visitor, client_data, ++ /*VisitPreprocessorLast=*/false, ++ /*VisitIncludedPreprocessingEntries=*/false, ++ /*RegionOfInterest=*/SourceRange(), ++ /*VisitDeclsOnly=*/false, ++ /*PostChildrenVisitor=*/nullptr, ++ /*VisitImplicitDeclarations=*/(options & CXVisitChildren_WithImplicit), ++ /*VisitTemplateInstantiations=*/ ++ (options & CXVisitChildren_WithTemplateInstantiations)); ++ ++ return CursorVis.VisitChildren(parent); ++} ++ + static CXString getDeclSpelling(const Decl *D) { + if (!D) + return cxstring::createEmpty(); +@@ -5909,6 +5970,22 @@ unsigned clang_isUnexposed(enum CXCursor + } + } + ++unsigned clang_isImplicit(CXCursor Cursor) { ++ if (clang_isInvalid(Cursor.kind)) ++ return false; ++ ++ if (!clang_isDeclaration(Cursor.kind)) ++ return false; ++ ++ const Decl *D = getCursorDecl(Cursor); ++ if (!D) { ++ assert(0 && "Invalid declaration cursor"); ++ return true; // abort. ++ } ++ ++ return D->isImplicit(); ++} ++ + CXCursorKind clang_getCursorKind(CXCursor C) { return C.kind; } + + CXSourceLocation clang_getCursorLocation(CXCursor C) { +diff --git a/tools/clang/tools/libclang/CursorVisitor.h b/clang/tools/libclang/CursorVisitor.h +index b0afa5a0b59..94f4596d5fa 100644 +--- a/tools/clang/tools/libclang/CursorVisitor.h ++++ b/tools/clang/tools/libclang/CursorVisitor.h +@@ -95,6 +95,12 @@ private: + /// record entries. + bool VisitDeclsOnly; + ++ /// \brief Whether we should visit implicit declarations. ++ bool VisitImplicitDeclarations; ++ ++ /// \brief Whether we should recurse into template instantiations. ++ bool VisitTemplateInstantiations; ++ + // FIXME: Eventually remove. This part of a hack to support proper + // iteration over all Decls contained lexically within an ObjC container. + DeclContext::decl_iterator *DI_current; +@@ -152,12 +152,16 @@ public: + bool VisitIncludedPreprocessingEntries = false, + SourceRange RegionOfInterest = SourceRange(), + bool VisitDeclsOnly = false, +- PostChildrenVisitorTy PostChildrenVisitor = nullptr) ++ PostChildrenVisitorTy PostChildrenVisitor = nullptr, ++ bool VisitImplicitDeclarations = false, ++ bool VisitTemplateInstantiations = false) + : TU(TU), AU(cxtu::getASTUnit(TU)), Visitor(Visitor), + PostChildrenVisitor(PostChildrenVisitor), ClientData(ClientData), + VisitPreprocessorLast(VisitPreprocessorLast), + VisitIncludedEntities(VisitIncludedPreprocessingEntries), + RegionOfInterest(RegionOfInterest), VisitDeclsOnly(VisitDeclsOnly), ++ VisitImplicitDeclarations(VisitImplicitDeclarations), ++ VisitTemplateInstantiations(VisitTemplateInstantiations), + DI_current(nullptr), FileDI_current(nullptr) { + Parent.kind = CXCursor_NoDeclFound; + Parent.data[0] = nullptr; +diff --git a/tools/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports +index 6af6c0ca3e8..d17eb83187d 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -313,6 +313,7 @@ clang_isInvalidDeclaration + clang_isExpression + clang_isFileMultipleIncludeGuarded + clang_isFunctionTypeVariadic ++clang_isImplicit + clang_isInvalid + clang_isPODType + clang_isPreprocessing +@@ -354,6 +355,7 @@ clang_CompileCommand_getNumArgs + clang_CompileCommand_getArg + clang_visitChildren + clang_visitChildrenWithBlock ++clang_visitChildrenWithOptions + clang_ModuleMapDescriptor_create + clang_ModuleMapDescriptor_dispose + clang_ModuleMapDescriptor_setFrameworkModuleName +-- +2.23.0 + diff --git a/packages/llvm/package.py b/packages/llvm/package.py index 9649b55746c959849df6fb0aafd1610d0c4e6a93..f9f1d6ba2e227605ef5c55f073d9bc8e1e54395f 100644 --- a/packages/llvm/package.py +++ b/packages/llvm/package.py @@ -174,17 +174,23 @@ class Llvm(CMakePackage, CudaPackage): patch('llvm7-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch', when='@7.0:7.999 +visionary', level=2) patch('llvm7-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch', when='@7.0:7.999 +visionary', level=2) - patch('llvm9-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch', when='@9.0:10.999 +visionary', level=2) + patch('llvm9-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch', when='@9.0.0:12.0.999 +visionary', level=2) patch('llvm9-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch', when='@9.0:10.999 +visionary', level=2) patch('llvm9-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch', when='@9.0:10.999 +visionary', level=2) patch('llvm9-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch', when='@9.0:10.999 +visionary', level=2) patch('llvm9-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch', when='@9.0:10.999 +visionary', level=2) - patch('llvm9-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch', when='@11.0:11.999 +visionary', level=2) - patch('llvm11-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch', when='@11.0:11.999 +visionary', level=2) - patch('llvm11-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch', when='@11.0:11.999 +visionary', level=2) - patch('llvm11-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch', when='@11.0:11.999 +visionary', level=2) - patch('llvm11-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch', when='@11.0:11.999 +visionary', level=2) + # 0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch from above + patch('llvm11-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch', when='@11.0.0:11.0.999 +visionary', level=2) + patch('llvm11-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch', when='@11.0.0:11.0.999 +visionary', level=2) + patch('llvm11-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch', when='@11.0.0:11.0.999 +visionary', level=2) + patch('llvm11-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch', when='@11.0.0:12.0.999 +visionary', level=2) + + # 0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch from above + patch('llvm11_1-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch', when='@11.1.0:12.0.999 +visionary', level=2) + patch('llvm11_1-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch', when='@11.1.0:12.0.999 +visionary', level=2) + patch('llvm11_1-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch', when='@11.1.0:12.0.999 +visionary', level=2) + # 0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch from above # Build dependency depends_on("cmake@3.4.3:", type="build")