diff --git a/packages/genpybind/package.py b/packages/genpybind/package.py new file mode 100644 index 0000000000000000000000000000000000000000..a50c4b57da01421f0d9bc32f8ddf3e5dcd51f7ac --- /dev/null +++ b/packages/genpybind/package.py @@ -0,0 +1,61 @@ +############################################################################## +# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/spack/spack +# Please also see the NOTICE and LICENSE files for our notice and the LGPL. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, February 1999. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and +# conditions of the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## +from spack import * + + +class Genpybind(WafPackage): + """Autogeneration of Python bindings from manually annotated C++ headers""" + + homepage = "https://github.com/kljohann/genpybind" + url = "https://github.com/kljohann/genpybind/archive/v0.1.0.tar.gz" + git = "https://github.com/kljohann/genpybind.git" + + version('0.2.1', sha256='e4d993f0c65cb5cf635cec7df899cbd91af1f0bd8a3626f33e9e0925f5383384') + version('0.2.0', sha256='9d1e9d026a9e355e282aca549a2af108bedcc5bc59ba0b76a6072f88e4c0be4c') + version('0.1.1-pre', commit="9d06a3ad4b6b917c8fcc07261a97b13a3079bcba") + version('0.1.0', sha256='f25cb2b3180103cb96c42fb8d37be8b1f06b7721f6aa08841d5ae16361896407') + version('master', branch='master') + version('develop', branch='develop') + + 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', + type=('build', 'link', 'run')) + depends_on('binutils', type='build') + depends_on('python@2.7:', type=('build', 'run')) + + extends('python') + + def configure_args(self): + args = super(Genpybind, self).configure_args() + + if self.spec.satisfies("@visions"): + # currently only our HEAD supports the rename + # TODO: adapt once the change is upstream + args.append("--genpybind-disable-tests") + else: + args.append("--disable-tests") + return args diff --git a/packages/llvm/constexpr_longdouble.patch b/packages/llvm/constexpr_longdouble.patch new file mode 100644 index 0000000000000000000000000000000000000000..f825b1421009f1698761943028214564f82ac825 --- /dev/null +++ b/packages/llvm/constexpr_longdouble.patch @@ -0,0 +1,15 @@ +--- a/libcxx/include/thread ++++ b/libcxx/include/thread +@@ -435,7 +435,12 @@ sleep_for(const chrono::duration<_Rep, _Period>& __d) + using namespace chrono; + if (__d > duration<_Rep, _Period>::zero()) + { ++#if ! (defined(_LIBCPP_COMPILER_GCC) && (__powerpc__ || __POWERPC__)) ++ // GCC's long double const folding is incomplete for IBM128 long doubles. + _LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max(); ++#else ++ _LIBCPP_CONSTEXPR duration<long double> _Max = duration<long double>(ULLONG_MAX/1000000000ULL) ; ++#endif + nanoseconds __ns; + if (__d < _Max) + { diff --git a/packages/llvm/constexpr_longdouble_9.0.patch b/packages/llvm/constexpr_longdouble_9.0.patch new file mode 100644 index 0000000000000000000000000000000000000000..bbc5ab7385e54c7269848b0a7a71bb3bac22d552 --- /dev/null +++ b/packages/llvm/constexpr_longdouble_9.0.patch @@ -0,0 +1,12 @@ +-- a/libcxx/include/thread ++++ b/libcxx/include/thread +@@ -370,7 +370,7 @@ sleep_for(const chrono::duration<_Rep, _Period>& __d) + using namespace chrono; + if (__d > duration<_Rep, _Period>::zero()) + { +-#if defined(_LIBCPP_COMPILER_GCC) && (__powerpc__ || __POWERPC__) ++#if ! (defined(_LIBCPP_COMPILER_GCC) && (__powerpc__ || __POWERPC__)) + // GCC's long double const folding is incomplete for IBM128 long doubles. + _LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max(); + #else + diff --git a/packages/llvm/lldb_external_ncurses-10.patch b/packages/llvm/lldb_external_ncurses-10.patch new file mode 100644 index 0000000000000000000000000000000000000000..34ed0e3cd2130cb18e0f72e86e5db1aace562787 --- /dev/null +++ b/packages/llvm/lldb_external_ncurses-10.patch @@ -0,0 +1,31 @@ +diff --git a/lldb/include/lldb/Host/Config.h.cmake b/lldb/include/lldb/Host/Config.h.cmake +--- a/lldb/include/lldb/Host/Config.h.cmake ++++ b/lldb/include/lldb/Host/Config.h.cmake +@@ -38,6 +38,8 @@ + + #cmakedefine01 LLDB_ENABLE_CURSES + ++#cmakedefine01 CURSES_HAVE_NCURSES_CURSES_H ++ + #cmakedefine01 LLDB_ENABLE_LIBEDIT + + #cmakedefine01 LLDB_ENABLE_LIBXML2 +diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp +--- a/lldb/source/Core/IOHandlerCursesGUI.cpp ++++ b/lldb/source/Core/IOHandlerCursesGUI.cpp +@@ -10,9 +10,14 @@ + #include "lldb/Host/Config.h" + + #if LLDB_ENABLE_CURSES ++#if CURSES_HAVE_NCURSES_CURSES_H ++#include <ncurses/curses.h> ++#include <ncurses/panel.h> ++#else + #include <curses.h> + #include <panel.h> + #endif ++#endif + + #if defined(__APPLE__) + #include <deque> + diff --git a/packages/llvm/llvm11-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch b/packages/llvm/llvm11-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch new file mode 100644 index 0000000000000000000000000000000000000000..8946be6a511291cd05dafcb925d8ce60dfa063de --- /dev/null +++ b/packages/llvm/llvm11-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 60 ++#define CINDEX_VERSION_MINOR 61 + + #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-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch b/packages/llvm/llvm11-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch new file mode 100644 index 0000000000000000000000000000000000000000..03b410710f1ed20e969ecf7dd00bbc76a4c703db --- /dev/null +++ b/packages/llvm/llvm11-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 61 ++#define CINDEX_VERSION_MINOR 62 + + #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-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch b/packages/llvm/llvm11-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b2d0e693e60e0ae8bdb93b16b93e419c928472d --- /dev/null +++ b/packages/llvm/llvm11-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 62 ++#define CINDEX_VERSION_MINOR 63 + + #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/llvm11-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch b/packages/llvm/llvm11-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch new file mode 100644 index 0000000000000000000000000000000000000000..47f035993becf92561a8a9703c5da6925050a5d7 --- /dev/null +++ b/packages/llvm/llvm11-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch @@ -0,0 +1,52 @@ +From 0fa84bbd8c6f8eb8eb6a3bc30e4efe3f2cf4c283 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Mon, 31 Jul 2017 14:09:52 +0200 +Subject: [PATCH 5/5] [libclang] WIP: Fix get_tokens in macro expansion + +--- + clang/bindings/python/tests/cindex/test_cursor.py | 15 +++++++++++++++ + clang/tools/libclang/CIndex.cpp | 2 +- + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py +index d061f37c25c..38702df74f2 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -552,6 +552,21 @@ class TestCursor(unittest.TestCase): + r_cursor = t_cursor.referenced # should not raise an exception + self.assertEqual(r_cursor.kind, CursorKind.CLASS_DECL) + ++ def test_get_tokens_in_macro_expansion(self): ++ """regression test""" ++ source = "#define IMPL(name) struct name { name(int v = 123); }; \n IMPL(X)" ++ tu = get_tu(source, lang="cpp") ++ ctor = get_cursors(tu, "X")[1] ++ self.assertEqual(ctor.kind, CursorKind.CONSTRUCTOR) ++ p = next(ctor.get_children()) ++ self.assertEqual(p.kind, CursorKind.PARM_DECL, (p.kind, p.spelling)) ++ children = list(p.get_children()) ++ self.assertEqual(len(children), 1, [(c.kind, c.spelling) for c in children]) ++ expr = children[0] ++ tokens = list(expr.get_tokens()) ++ self.assertEqual(len(tokens), 1, [t.spelling for t in tokens]) ++ self.assertEqual(tokens[0].spelling, "123") ++ + def test_get_arguments(self): + tu = get_tu('void foo(int i, int j);') + foo = get_cursor(tu, 'foo') +diff --git a/tools/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp +index 7ee6b704647..e4b95436704 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -147,7 +147,7 @@ CXSourceRange cxloc::translateSourceRang + // location accordingly. + SourceLocation EndLoc = R.getEnd(); + bool IsTokenRange = R.isTokenRange(); +- if (EndLoc.isValid() && EndLoc.isMacroID() && ++ if (false && EndLoc.isValid() && EndLoc.isMacroID() && + !SM.isMacroArgExpansion(EndLoc)) { + CharSourceRange Expansion = SM.getExpansionRange(EndLoc); + EndLoc = Expansion.getEnd(); +-- +2.23.0 + diff --git a/packages/llvm/llvm5-0001-libclang-Add-support-for-checking-abstractness-of-re.patch b/packages/llvm/llvm5-0001-libclang-Add-support-for-checking-abstractness-of-re.patch new file mode 100644 index 0000000000000000000000000000000000000000..62aabd59000ea8e99255a341945fc76ddfffbf74 --- /dev/null +++ b/packages/llvm/llvm5-0001-libclang-Add-support-for-checking-abstractness-of-re.patch @@ -0,0 +1,146 @@ +From 85f611be67af9f9b5677917b4fee5bd15b5dc394 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de> +Date: Mon, 31 Jul 2017 14:09:08 +0200 +Subject: [PATCH 01/12] [libclang] Add support for checking abstractness of + records + +--- + bindings/python/clang/cindex.py | 10 ++++++++++ + bindings/python/tests/cindex/test_cursor.py | 11 +++++++++++ + include/clang-c/Index.h | 6 ++++++ + test/Index/load-classes.cpp | 2 +- + tools/c-index-test/c-index-test.c | 2 ++ + tools/libclang/CIndex.cpp | 11 +++++++++++ + tools/libclang/libclang.exports | 1 + + 7 files changed, 42 insertions(+), 1 deletion(-) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py +index 236803a9ab..0f01d171ad 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -1478,6 +1478,12 @@ class Cursor(Structure): + """ + return conf.lib.clang_CXXMethod_isVirtual(self) + ++ def is_abstract_record(self): ++ """Returns True if the cursor refers to a C++ record declaration ++ that has pure virtual member functions. ++ """ ++ return conf.lib.clang_CXXRecord_isAbstract(self) ++ + def is_scoped_enum(self): + """Returns True if the cursor refers to a scoped enum declaration. + """ +@@ -3319,6 +3325,10 @@ functionList = [ + [Cursor], + bool), + ++ ("clang_CXXRecord_isAbstract", ++ [Cursor], ++ bool), ++ + ("clang_EnumDecl_isScoped", + [Cursor], + bool), +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/tools/clang/bindings/python/tests/cindex/test_cursor.py +index 4787ea931e..85c455fd73 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -255,6 +255,17 @@ def test_is_virtual_method(): + assert foo.is_virtual_method() + assert not bar.is_virtual_method() + ++def test_is_abstract_record(): ++ """Ensure Cursor.is_abstract_record works.""" ++ source = 'struct X { virtual void x() = 0; }; struct Y : X { void x(); };' ++ tu = get_tu(source, lang='cpp') ++ ++ cls = get_cursor(tu, 'X') ++ assert cls.is_abstract_record() ++ ++ cls = get_cursor(tu, 'Y') ++ assert not cls.is_abstract_record() ++ + def test_is_scoped_enum(): + """Ensure Cursor.is_scoped_enum works.""" + source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};' +diff --git a/tools/clang/include/clang-c/Index.h b/tools/clang/include/clang-c/Index.h +index 3b5ea9fa53..89957e8526 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -4419,6 +4419,12 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C); + CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C); + + /** ++ * \brief Determine if a C++ record is abstract, i.e. whether a class or struct ++ * has a pure virtual member function. ++ */ ++CINDEX_LINKAGE unsigned clang_CXXRecord_isAbstract(CXCursor C); ++ ++/** + * \brief Determine if an enum declaration refers to a scoped enum. + */ + CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C); +diff --git a/tools/clang/test/Index/load-classes.cpp b/tools/clang/test/Index/load-classes.cpp +index 8b1ed317e3..b6c25b4f75 100644 +--- a/tools/clang/test/Index/load-classes.cpp ++++ b/tools/clang/test/Index/load-classes.cpp +@@ -29,7 +29,7 @@ X::X(int value) { + } + + // RUN: c-index-test -test-load-source all %s | FileCheck %s +-// CHECK: load-classes.cpp:3:8: StructDecl=X:3:8 (Definition) Extent=[3:1 - 26:2] ++// CHECK: load-classes.cpp:3:8: StructDecl=X:3:8 (Definition) (abstract) Extent=[3:1 - 26:2] + // CHECK: load-classes.cpp:4:3: CXXConstructor=X:4:3 (converting constructor) Extent=[4:3 - 4:15] [access=public] + // FIXME: missing TypeRef in the constructor name + // CHECK: load-classes.cpp:4:9: ParmDecl=value:4:9 (Definition) Extent=[4:5 - 4:14] +diff --git a/tools/clang/tools/c-index-test/c-index-test.c b/tools/clang/tools/c-index-test/c-index-test.c +index cf3581e259..08a187ffdd 100644 +--- a/tools/clang/tools/c-index-test/c-index-test.c ++++ b/tools/clang/tools/c-index-test/c-index-test.c +@@ -804,6 +804,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { + printf(" (const)"); + if (clang_CXXMethod_isPureVirtual(Cursor)) + printf(" (pure)"); ++ if (clang_CXXRecord_isAbstract(Cursor)) ++ printf(" (abstract)"); + if (clang_EnumDecl_isScoped(Cursor)) + printf(" (scoped)"); + if (clang_Cursor_isVariadic(Cursor)) +diff --git a/tools/clang/tools/libclang/CIndex.cpp b/tools/clang/tools/libclang/CIndex.cpp +index ca21b6c6f6..621bc42076 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -7846,6 +7846,17 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) { + return (Method && Method->isVirtual()) ? 1 : 0; + } + ++unsigned clang_CXXRecord_isAbstract(CXCursor C) { ++ if (!clang_isDeclaration(C.kind)) ++ return 0; ++ ++ const auto *D = cxcursor::getCursorDecl(C); ++ const auto *RD = dyn_cast_or_null<CXXRecordDecl>(D); ++ if (RD) ++ RD = RD->getDefinition(); ++ return (RD && RD->isAbstract()) ? 1 : 0; ++} ++ + unsigned clang_EnumDecl_isScoped(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; +diff --git a/tools/clang/tools/libclang/libclang.exports b/tools/clang/tools/libclang/libclang.exports +index e0d178a529..9ddc055125 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -12,6 +12,7 @@ clang_CXXMethod_isConst + clang_CXXMethod_isPureVirtual + clang_CXXMethod_isStatic + clang_CXXMethod_isVirtual ++clang_CXXRecord_isAbstract + clang_EnumDecl_isScoped + clang_Cursor_getArgument + clang_Cursor_getNumTemplateArguments +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0002-libclang-Keep-track-of-TranslationUnit-instance-when.patch b/packages/llvm/llvm5-0002-libclang-Keep-track-of-TranslationUnit-instance-when.patch new file mode 100644 index 0000000000000000000000000000000000000000..d5d076234c36c8d14daeb86b80f1e7553f258161 --- /dev/null +++ b/packages/llvm/llvm5-0002-libclang-Keep-track-of-TranslationUnit-instance-when.patch @@ -0,0 +1,61 @@ +From 0c4382f31fefe6c5575842427c83e1c26fe00efa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de> +Date: Fri, 28 Jul 2017 12:25:20 +0200 +Subject: [PATCH 02/12] [libclang] Keep track of TranslationUnit instance when + annotating tokens + +Previously the _tu was not propagated to the returned cursor, leading to errors when calling any +method on that cursor (e.g. cursor.referenced). +--- + bindings/python/clang/cindex.py | 1 + + bindings/python/tests/cindex/test_cursor.py | 22 ++++++++++++++++++++++ + 2 files changed, 23 insertions(+) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py +index 0f01d171ad..ecff13f7a5 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -3199,6 +3199,7 @@ class Token(Structure): + def cursor(self): + """The Cursor this Token corresponds to.""" + cursor = Cursor() ++ cursor._tu = self._tu + + conf.lib.clang_annotateTokens(self._tu, byref(self), 1, byref(cursor)) + +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/tools/clang/bindings/python/tests/cindex/test_cursor.py +index 85c455fd73..87fd76ed0e 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -406,6 +406,28 @@ def test_get_tokens(): + assert tokens[0].spelling == 'int' + assert tokens[1].spelling == 'foo' + ++def test_get_token_cursor(): ++ """Ensure we can map tokens to cursors.""" ++ tu = get_tu('class A {}; int foo(A var = A());', lang='cpp') ++ foo = get_cursor(tu, 'foo') ++ ++ for cursor in foo.walk_preorder(): ++ if cursor.kind.is_expression() and not cursor.kind.is_statement(): ++ break ++ else: ++ assert False, "Could not find default value expression" ++ ++ tokens = list(cursor.get_tokens()) ++ assert len(tokens) == 4, [t.spelling for t in tokens] ++ assert tokens[0].spelling == '=' ++ assert tokens[1].spelling == 'A' ++ assert tokens[2].spelling == '(' ++ assert tokens[3].spelling == ')' ++ t_cursor = tokens[1].cursor ++ assert t_cursor.kind == CursorKind.TYPE_REF ++ r_cursor = t_cursor.referenced # should not raise an exception ++ assert r_cursor.kind == CursorKind.CLASS_DECL ++ + def test_get_arguments(): + tu = get_tu('void foo(int i, int j);') + foo = get_cursor(tu, 'foo') +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0003-Fix-warnings-in-Tooling-QualTypeNamesTest.patch b/packages/llvm/llvm5-0003-Fix-warnings-in-Tooling-QualTypeNamesTest.patch new file mode 100644 index 0000000000000000000000000000000000000000..2fa9a8c80ce5aeffb04977ce941395bdc6543fa3 --- /dev/null +++ b/packages/llvm/llvm5-0003-Fix-warnings-in-Tooling-QualTypeNamesTest.patch @@ -0,0 +1,57 @@ +From 1ef6a85f73cb4f06405dfe20c225bcc0da9f9776 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Wed, 26 Jul 2017 15:09:28 +0200 +Subject: [PATCH 03/12] Fix warnings in Tooling/QualTypeNamesTest + +The code in question uses variadic templates and alias declarations +and thus needs `-std=c++11`. +--- + unittests/Tooling/QualTypeNamesTest.cpp | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp b/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp +index edd5060ba0..532fae6f5a 100644 +--- a/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp ++++ b/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp +@@ -35,7 +35,7 @@ struct TypeNameVisitor : TestVisitor<TypeNameVisitor> { + EXPECT_TRUE(false) << "Typename::getFullyQualifiedName failed for " + << VD->getQualifiedNameAsString() << std::endl + << " Actual: " << ActualName << std::endl +- << " Exepcted: " << ExpectedName; ++ << " Expected: " << ExpectedName; + } + } + return true; +@@ -163,7 +163,7 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + "};\n" + "EnumScopeClass::AnEnum AnEnumVar;\n", + TypeNameVisitor::Lang_CXX11 +-); ++ ); + + TypeNameVisitor Complex; + Complex.ExpectedQualTypeNames["CheckTX"] = "B::TX"; +@@ -180,7 +180,9 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + " typedef tuple<X> TX;" + " TX CheckTX;" + " struct A { typedef int X; };" +- "}"); ++ "}", ++ TypeNameVisitor::Lang_CXX11 ++ ); + + TypeNameVisitor GlobalNsPrefix; + GlobalNsPrefix.WithGlobalNsPrefix = true; +@@ -215,7 +217,8 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + " aStruct CheckK;\n" + " }\n" + " }\n" +- "}\n" ++ "}\n", ++ TypeNameVisitor::Lang_CXX11 + ); + } + +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0004-Defer-addition-of-keywords-to-identifier-table-when-.patch b/packages/llvm/llvm5-0004-Defer-addition-of-keywords-to-identifier-table-when-.patch new file mode 100644 index 0000000000000000000000000000000000000000..426b22fdbca50d1ab82a8dafd8355dcd9217e490 --- /dev/null +++ b/packages/llvm/llvm5-0004-Defer-addition-of-keywords-to-identifier-table-when-.patch @@ -0,0 +1,220 @@ +From ba4c926983036f010c3e4d28be48cfdee8495f87 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de> +Date: Sun, 9 Jul 2017 13:03:02 +0200 +Subject: [PATCH 04/12] Defer addition of keywords to identifier table when + loading AST + +In ASTUnit::LoadFromASTFile, the preprocesor object is set up using +default-constructed LangOptions (which only later get populated). +Then, in the constructor of IdentifierTable, these default-constructed +LangOptions were used in the call to AddKeywords, leading to wrong +initialization of the identifier table. + +This change defers adding the keywords to the identifier table until +after the language options have been loaded from the AST file. +--- + include/clang/Basic/IdentifierTable.h | 6 ++-- + include/clang/Lex/Preprocessor.h | 3 +- + lib/Basic/IdentifierTable.cpp | 17 +++++----- + lib/Frontend/ASTUnit.cpp | 10 ++++-- + lib/Lex/Preprocessor.cpp | 6 ++-- + unittests/libclang/LibclangTest.cpp | 64 +++++++++++++++++++++++++++++++++++ + 6 files changed, 91 insertions(+), 15 deletions(-) + +diff --git a/tools/clang/include/clang/Basic/IdentifierTable.h b/tools/clang/include/clang/Basic/IdentifierTable.h +index 3938e09890..1172869d45 100644 +--- a/tools/clang/include/clang/Basic/IdentifierTable.h ++++ b/tools/clang/include/clang/Basic/IdentifierTable.h +@@ -472,9 +472,11 @@ class IdentifierTable { + + public: + /// \brief Create the identifier table, populating it with info about the +- /// language keywords for the language specified by \p LangOpts. ++ /// language keywords for the language specified by \p LangOpts if ++ /// \p DeferKeywordAddition is not set. + IdentifierTable(const LangOptions &LangOpts, +- IdentifierInfoLookup* externalLookup = nullptr); ++ IdentifierInfoLookup *externalLookup = nullptr, ++ bool DeferKeywordAddition = false); + + /// \brief Set the external identifier lookup mechanism. + void setExternalIdentifierLookup(IdentifierInfoLookup *IILookup) { +diff --git a/tools/clang/include/clang/Lex/Preprocessor.h b/tools/clang/include/clang/Lex/Preprocessor.h +index 49a95986fd..6570e4c76e 100644 +--- a/tools/clang/include/clang/Lex/Preprocessor.h ++++ b/tools/clang/include/clang/Lex/Preprocessor.h +@@ -692,7 +692,8 @@ public: + HeaderSearch &Headers, ModuleLoader &TheModuleLoader, + IdentifierInfoLookup *IILookup = nullptr, + bool OwnsHeaderSearch = false, +- TranslationUnitKind TUKind = TU_Complete); ++ TranslationUnitKind TUKind = TU_Complete, ++ bool DeferKeywordAddition = false); + + ~Preprocessor(); + +diff --git a/tools/clang/lib/Basic/IdentifierTable.cpp b/tools/clang/lib/Basic/IdentifierTable.cpp +index fe7829ec50..cfb0b1a702 100644 +--- a/tools/clang/lib/Basic/IdentifierTable.cpp ++++ b/tools/clang/lib/Basic/IdentifierTable.cpp +@@ -73,17 +73,15 @@ IdentifierIterator *IdentifierInfoLookup::getIdentifiers() { + } + + IdentifierTable::IdentifierTable(const LangOptions &LangOpts, +- IdentifierInfoLookup* externalLookup) +- : HashTable(8192), // Start with space for 8K identifiers. +- ExternalLookup(externalLookup) { ++ IdentifierInfoLookup *externalLookup, ++ bool DeferKeywordAddition) ++ : HashTable(8192), // Start with space for 8K identifiers. ++ ExternalLookup(externalLookup) { + + // Populate the identifier table with info about keywords for the current + // language. +- AddKeywords(LangOpts); +- +- +- // Add the '_experimental_modules_import' contextual keyword. +- get("import").setModulesImport(true); ++ if (!DeferKeywordAddition) ++ AddKeywords(LangOpts); + } + + //===----------------------------------------------------------------------===// +@@ -230,6 +228,9 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { + + if (LangOpts.DeclSpecKeyword) + AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this); ++ ++ // Add the '_experimental_modules_import' contextual keyword. ++ get("import").setModulesImport(true); + } + + /// \brief Checks if the specified token kind represents a keyword in the +diff --git a/tools/clang/lib/Frontend/ASTUnit.cpp b/tools/clang/lib/Frontend/ASTUnit.cpp +index 07f847ca94..875f21d69a 100644 +--- a/tools/clang/lib/Frontend/ASTUnit.cpp ++++ b/tools/clang/lib/Frontend/ASTUnit.cpp +@@ -536,6 +536,10 @@ private: + // Initialize the preprocessor. + PP.Initialize(*Target); + ++ // Populate the identifier table with info about keywords for the current ++ // language. ++ PP.getIdentifierTable().AddKeywords(LangOpt); ++ + if (!Context) + return; + +@@ -718,11 +722,13 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( + HeaderSearch &HeaderInfo = *AST->HeaderInfo; + unsigned Counter; + ++ // As the language options have not been loaded yet, adding keywords to the ++ // identifier table is deferred and will be initiated by ASTInfoCollector. + AST->PP = std::make_shared<Preprocessor>( + AST->PPOpts, AST->getDiagnostics(), *AST->LangOpts, + AST->getSourceManager(), *AST->PCMCache, HeaderInfo, AST->ModuleLoader, +- /*IILookup=*/nullptr, +- /*OwnsHeaderSearch=*/false); ++ /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false, TU_Complete, ++ /*DeferKeywordAddition=*/true); + Preprocessor &PP = *AST->PP; + + if (ToLoad >= LoadASTOnly) +diff --git a/tools/clang/lib/Lex/Preprocessor.cpp b/tools/clang/lib/Lex/Preprocessor.cpp +index 158d0eca27..64365385a3 100644 +--- a/tools/clang/lib/Lex/Preprocessor.cpp ++++ b/tools/clang/lib/Lex/Preprocessor.cpp +@@ -73,12 +73,14 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, + SourceManager &SM, MemoryBufferCache &PCMCache, + HeaderSearch &Headers, ModuleLoader &TheModuleLoader, + IdentifierInfoLookup *IILookup, bool OwnsHeaders, +- TranslationUnitKind TUKind) ++ TranslationUnitKind TUKind, ++ bool DeferKeywordAddition) + : PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), Target(nullptr), + AuxTarget(nullptr), FileMgr(Headers.getFileMgr()), SourceMgr(SM), + PCMCache(PCMCache), ScratchBuf(new ScratchBuffer(SourceMgr)), + HeaderInfo(Headers), TheModuleLoader(TheModuleLoader), +- ExternalSource(nullptr), Identifiers(opts, IILookup), ++ ExternalSource(nullptr), ++ Identifiers(opts, IILookup, DeferKeywordAddition), + PragmaHandlers(new PragmaNamespace(StringRef())), + IncrementalProcessing(false), TUKind(TUKind), CodeComplete(nullptr), + CodeCompletionFile(nullptr), CodeCompletionOffset(0), +diff --git a/tools/clang/unittests/libclang/LibclangTest.cpp b/tools/clang/unittests/libclang/LibclangTest.cpp +index f2a96d6be6..27c8ac7b3d 100644 +--- a/tools/clang/unittests/libclang/LibclangTest.cpp ++++ b/tools/clang/unittests/libclang/LibclangTest.cpp +@@ -572,3 +572,67 @@ TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) { + EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); + DisplayDiagnostics(); + } ++ ++class LibclangSerializationTest : public LibclangParseTest { ++public: ++ bool SaveAndLoadTU(const std::string &Filename) { ++ unsigned options = clang_defaultSaveOptions(ClangTU); ++ if (clang_saveTranslationUnit(ClangTU, Filename.c_str(), options) != ++ CXSaveError_None) { ++ DEBUG(llvm::dbgs() << "Saving failed\n"); ++ return false; ++ } ++ ++ clang_disposeTranslationUnit(ClangTU); ++ ++ ClangTU = clang_createTranslationUnit(Index, Filename.c_str()); ++ ++ if (!ClangTU) { ++ DEBUG(llvm::dbgs() << "Loading failed\n"); ++ return false; ++ } ++ ++ return true; ++ } ++}; ++ ++TEST_F(LibclangSerializationTest, TokenKindsAreCorrectAfterLoading) { ++ // Ensure that "class" is recognized as a keyword token after serializing ++ // and reloading the AST, as it is not a keyword for the default LangOptions. ++ std::string HeaderName = "test.h"; ++ WriteFile(HeaderName, "enum class Something {};"); ++ ++ const char *Argv[] = {"-xc++-header", "-std=c++11"}; ++ ++ ClangTU = clang_parseTranslationUnit(Index, HeaderName.c_str(), Argv, ++ sizeof(Argv) / sizeof(Argv[0]), nullptr, ++ 0, TUFlags); ++ ++ auto CheckTokenKinds = [=]() { ++ CXSourceRange Range = ++ clang_getCursorExtent(clang_getTranslationUnitCursor(ClangTU)); ++ ++ CXToken *Tokens; ++ unsigned int NumTokens; ++ clang_tokenize(ClangTU, Range, &Tokens, &NumTokens); ++ ++ ASSERT_EQ(6u, NumTokens); ++ EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[0])); ++ EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[1])); ++ EXPECT_EQ(CXToken_Identifier, clang_getTokenKind(Tokens[2])); ++ EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[3])); ++ EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[4])); ++ EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[5])); ++ ++ clang_disposeTokens(ClangTU, Tokens, NumTokens); ++ }; ++ ++ CheckTokenKinds(); ++ ++ std::string ASTName = "test.ast"; ++ WriteFile(ASTName, ""); ++ ++ ASSERT_TRUE(SaveAndLoadTU(ASTName)); ++ ++ CheckTokenKinds(); ++} +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0005-Tooling-Fully-qualify-template-parameters-of-nested-.patch b/packages/llvm/llvm5-0005-Tooling-Fully-qualify-template-parameters-of-nested-.patch new file mode 100644 index 0000000000000000000000000000000000000000..e23cb61895f88a3009cbc06cc5dd0d9006a0ef27 --- /dev/null +++ b/packages/llvm/llvm5-0005-Tooling-Fully-qualify-template-parameters-of-nested-.patch @@ -0,0 +1,77 @@ +From 4427624b30117c6db67b9ea7c3f16e396edc3748 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Wed, 26 Jul 2017 15:06:10 +0200 +Subject: [PATCH 05/12] [Tooling] Fully qualify template parameters of nested + name specifier in getFullyQualifiedName + +--- + lib/Tooling/Core/QualTypeNames.cpp | 18 ++++++++++++++---- + unittests/Tooling/QualTypeNamesTest.cpp | 8 +++++++- + 2 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/tools/clang/lib/Tooling/Core/QualTypeNames.cpp b/tools/clang/lib/Tooling/Core/QualTypeNames.cpp +index 721c2c92fc..934624dd14 100644 +--- a/tools/clang/lib/Tooling/Core/QualTypeNames.cpp ++++ b/tools/clang/lib/Tooling/Core/QualTypeNames.cpp +@@ -370,11 +370,21 @@ NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix) { ++ const Type *TypePtr = TD->getTypeForDecl(); ++ // In case of template specializations iterate over the arguments and ++ // fully qualify them as well. ++ if (isa<const TemplateSpecializationType>(TypePtr) || ++ isa<const RecordType>(TypePtr)) { ++ // We are asked to fully qualify and we have a Record Type (which ++ // may point to a template specialization) or Template ++ // Specialization Type. We need to fully qualify their arguments. ++ ++ TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); ++ } ++ + return NestedNameSpecifier::Create( +- Ctx, +- createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), +- false /*No TemplateKeyword*/, +- TD->getTypeForDecl()); ++ Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), ++ false /*No TemplateKeyword*/, TypePtr); + } + + /// \brief Return the fully qualified type, including fully-qualified +diff --git a/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp b/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp +index 532fae6f5a..e27089b986 100644 +--- a/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp ++++ b/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp +@@ -63,6 +63,10 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + // Template parameter expansion. + Visitor.ExpectedQualTypeNames["CheckC"] = + "A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>"; ++ // Template parameters of nested name specifier should also be fully expanded. ++ Visitor.ExpectedQualTypeNames["CheckNested"] = ++ // "typename A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>::nested"; ++ "typename A::B::Template0<int, A::B::Class0>::nested"; + // Recursive template parameter expansion. + Visitor.ExpectedQualTypeNames["CheckD"] = + "A::B::Template0<A::B::Template1<A::B::C::MyInt, A::B::AnotherClass>, " +@@ -105,7 +109,7 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + " using InnerAlias = OuterTemplateClass<T>;\n" + " InnerAlias<int> AliasTypeVal;\n" + " }\n" +- " template<class X, class Y> class Template0;" ++ " template<class X, class Y> struct Template0 { typedef int nested; };" + " template<class X, class Y> class Template1;" + " typedef B::Class0 AnotherClass;\n" + " void Function1(Template0<C::MyInt,\n" +@@ -113,6 +117,8 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + " void Function2(Template0<Template1<C::MyInt, AnotherClass>,\n" + " Template0<int, long> > CheckD);\n" + " void Function3(const B::Class0* CheckM);\n" ++ " void Function4(typename Template0<C::MyInt,\n" ++ " AnotherClass>::nested CheckNested);\n" + " }\n" + "template<typename... Values> class Variadic {};\n" + "Variadic<int, B::Template0<int, char>, " +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0006-libclang-Add-support-for-obtaining-fully-qualified-n.patch b/packages/llvm/llvm5-0006-libclang-Add-support-for-obtaining-fully-qualified-n.patch new file mode 100644 index 0000000000000000000000000000000000000000..441dc96ecf8216395359a5a207feea5e54063f06 --- /dev/null +++ b/packages/llvm/llvm5-0006-libclang-Add-support-for-obtaining-fully-qualified-n.patch @@ -0,0 +1,136 @@ +From a24d66fca11152dbd9b8abb246dfa340e2d6843b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de> +Date: Mon, 10 Jul 2017 13:53:25 +0200 +Subject: [PATCH 06/12] [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). +--- + bindings/python/clang/cindex.py | 13 +++++++++++++ + bindings/python/tests/cindex/test_cursor.py | 8 ++++++++ + include/clang-c/Index.h | 8 ++++++++ + tools/libclang/CXType.cpp | 18 ++++++++++++++++++ + tools/libclang/libclang.exports | 1 + + 5 files changed, 48 insertions(+) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py +index ecff13f7a5..496e1089ad 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -2314,6 +2314,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 +@@ -3750,6 +3758,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 87fd76ed0e..3cd499ea11 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -291,6 +291,14 @@ def test_underlying_type(): + underlying = typedef.underlying_typedef_type + assert 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') ++ assert cls.type.fully_qualified_name.endswith( ++ "uiae::X::sometype") ++ + kParentTest = """\ + class C { + void f(); +diff --git a/tools/clang/include/clang-c/Index.h b/tools/clang/include/clang-c/Index.h +index 89957e8526..402ca9a436 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -3241,6 +3241,14 @@ CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C); + CINDEX_LINKAGE CXString clang_getTypeSpelling(CXType CT); + + /** ++ * \brief 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); ++ ++/** + * \brief Retrieve the underlying type of a typedef declaration. + * + * If the cursor does not reference a typedef declaration, an invalid type is +diff --git a/tools/clang/tools/libclang/CXType.cpp b/tools/clang/tools/libclang/CXType.cpp +index d2cb509059..e99f513d13 100644 +--- a/tools/clang/tools/libclang/CXType.cpp ++++ b/tools/clang/tools/libclang/CXType.cpp +@@ -23,6 +23,7 @@ + #include "clang/AST/Type.h" + #include "clang/Basic/AddressSpaces.h" + #include "clang/Frontend/ASTUnit.h" ++#include "clang/Tooling/Core/QualTypeNames.h" + + using namespace clang; + +@@ -282,6 +283,23 @@ 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(); ++ std::string name = TypeName::getFullyQualifiedName(T, Ctx, /*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 9ddc055125..9c56e88052 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -221,6 +221,7 @@ clang_getFileLocation + clang_getFileName + clang_getFileTime + clang_getFileUniqueID ++clang_getFullyQualifiedTypeName + clang_getFunctionTypeCallingConv + clang_getIBOutletCollectionType + clang_getIncludedFile +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0007-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch b/packages/llvm/llvm5-0007-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch new file mode 100644 index 0000000000000000000000000000000000000000..d8625c32efa08e8ec47c430d4ec114dfda36b6da --- /dev/null +++ b/packages/llvm/llvm5-0007-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch @@ -0,0 +1,242 @@ +From 25c705cda6508b56ac4ab4ccd8c08a1a8f911941 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de> +Date: Mon, 10 Jul 2017 14:44:22 +0200 +Subject: [PATCH 07/12] [libclang] Add option to keep whitespace when + tokenizing + +--- + bindings/python/clang/cindex.py | 31 ++++++++++++++++++++++------- + bindings/python/tests/cindex/test_cursor.py | 9 +++++++++ + include/clang-c/Index.h | 30 ++++++++++++++++++++++++++-- + tools/libclang/CIndex.cpp | 13 ++++++++++-- + tools/libclang/libclang.exports | 1 + + 5 files changed, 73 insertions(+), 11 deletions(-) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py +index 496e1089ad..a5bb58b44f 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -514,6 +514,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 +@@ -523,7 +530,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 +@@ -532,8 +539,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) + +@@ -1801,13 +1808,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.""" +@@ -2971,18 +2981,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): + """ +@@ -3850,6 +3863,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/tools/clang/bindings/python/tests/cindex/test_cursor.py +index 3cd499ea11..2d50ec5901 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -3,6 +3,7 @@ import gc + + 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 +@@ -436,6 +437,14 @@ def test_get_token_cursor(): + r_cursor = t_cursor.referenced # should not raise an exception + assert r_cursor.kind == CursorKind.CLASS_DECL + ++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)) ++ assert ''.join(t.spelling for t in tokens) == source ++ assert len(tokens) == 27 ++ + def test_get_arguments(): + tu = get_tu('void foo(int i, int j);') + foo = get_cursor(tu, 'foo') +diff --git a/tools/clang/include/clang-c/Index.h b/tools/clang/include/clang-c/Index.h +index 402ca9a436..7fd17366ee 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -4616,6 +4616,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); ++ + /** + * \brief Tokenize the source code described by the given range into raw + * lexical tokens. +@@ -4632,9 +4654,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); + + /** + * \brief Annotate the given set of tokens by providing cursors for each token +diff --git a/tools/clang/tools/libclang/CIndex.cpp b/tools/clang/tools/libclang/CIndex.cpp +index 621bc42076..04fd775fb0 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -6292,7 +6292,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()); +@@ -6314,6 +6314,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; +@@ -6365,6 +6368,12 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range, + + 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; + } +@@ -6390,7 +6399,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/tools/clang/tools/libclang/libclang.exports +index 9c56e88052..b8e3df23ef 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -316,6 +316,7 @@ clang_suspendTranslationUnit + clang_sortCodeCompletionResults + clang_toggleCrashRecovery + clang_tokenize ++clang_tokenizeRange + clang_CompilationDatabase_fromDirectory + clang_CompilationDatabase_dispose + clang_CompilationDatabase_getCompileCommands +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0008-Fix-printing-policy-for-AST-context-loaded-from-file.patch b/packages/llvm/llvm5-0008-Fix-printing-policy-for-AST-context-loaded-from-file.patch new file mode 100644 index 0000000000000000000000000000000000000000..95ae8c9fc8bf36b8c094afd30ae6cc8abcd8c8ee --- /dev/null +++ b/packages/llvm/llvm5-0008-Fix-printing-policy-for-AST-context-loaded-from-file.patch @@ -0,0 +1,137 @@ +From f612539aaee3a46abbbc8fa30d0263d9b49dca86 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de> +Date: Mon, 10 Jul 2017 12:34:10 +0200 +Subject: [PATCH 08/12] Fix printing policy for AST context loaded from file + +In ASTUnit::LoadFromASTFile, the context object is set up using default-constructed +LangOptions (which only later get populated). As the language options are used in the constructor +of PrintingPolicy, this needs to be updated explicitly after the language options are available. +--- + lib/Frontend/ASTUnit.cpp | 3 ++ + unittests/Frontend/ASTUnitTest.cpp | 87 ++++++++++++++++++++++++++++++++++++++ + unittests/Frontend/CMakeLists.txt | 1 + + 3 files changed, 91 insertions(+) + create mode 100644 unittests/Frontend/ASTUnitTest.cpp + +diff --git a/tools/clang/lib/Frontend/ASTUnit.cpp b/tools/clang/lib/Frontend/ASTUnit.cpp +index 875f21d69a..bb1ea6c4f8 100644 +--- a/tools/clang/lib/Frontend/ASTUnit.cpp ++++ b/tools/clang/lib/Frontend/ASTUnit.cpp +@@ -546,6 +546,9 @@ private: + // Initialize the ASTContext + Context->InitBuiltinTypes(*Target); + ++ // Adjust printing policy based on language options. ++ Context->setPrintingPolicy(PrintingPolicy(LangOpt)); ++ + // We didn't have access to the comment options when the ASTContext was + // constructed, so register them now. + Context->getCommentCommandTraits().registerCommentOptions( +diff --git a/tools/clang/unittests/Frontend/ASTUnitTest.cpp b/tools/clang/unittests/Frontend/ASTUnitTest.cpp +new file mode 100644 +index 0000000000..a7d08a992f +--- /dev/null ++++ b/tools/clang/unittests/Frontend/ASTUnitTest.cpp +@@ -0,0 +1,87 @@ ++//===- unittests/Frontend/ASTUnitTest.cpp - ASTUnit tests -----------------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include <fstream> ++ ++#include "clang/Frontend/ASTUnit.h" ++#include "clang/Frontend/CompilerInstance.h" ++#include "clang/Frontend/CompilerInvocation.h" ++#include "clang/Frontend/PCHContainerOperations.h" ++#include "llvm/Support/FileSystem.h" ++#include "llvm/Support/Path.h" ++#include "llvm/Support/ToolOutputFile.h" ++#include "gtest/gtest.h" ++ ++using namespace llvm; ++using namespace clang; ++ ++namespace { ++ ++TEST(ASTUnit, SaveLoadPreservesLangOptionsInPrintingPolicy) { ++ // Check that the printing policy is restored with the correct language ++ // options when loading an ASTUnit from a file. To this end, an ASTUnit ++ // for a C++ translation unit is set up and written to a temporary file. ++ ++ // By default `UseVoidForZeroParams` is true for non-C++ language options, ++ // thus we can check this field after loading the ASTUnit to deduce whether ++ // the correct (C++) language options were used when setting up the printing ++ // policy. ++ ++ { ++ PrintingPolicy PolicyWithDefaultLangOpt(LangOptions{}); ++ EXPECT_TRUE(PolicyWithDefaultLangOpt.UseVoidForZeroParams); ++ } ++ ++ int FD; ++ llvm::SmallString<256> InputFileName; ++ ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("ast-unit", "cpp", FD, InputFileName)); ++ tool_output_file input_file(InputFileName, FD); ++ input_file.os() << ""; ++ ++ const char* Args[] = {"clang", "-xc++", InputFileName.c_str()}; ++ ++ IntrusiveRefCntPtr<DiagnosticsEngine> Diags = ++ CompilerInstance::createDiagnostics(new DiagnosticOptions()); ++ ++ std::shared_ptr<CompilerInvocation> CInvok = ++ createInvocationFromCommandLine(Args, Diags); ++ ++ if (!CInvok) ++ FAIL() << "could not create compiler invocation"; ++ ++ FileManager *FileMgr = ++ new FileManager(FileSystemOptions(), vfs::getRealFileSystem()); ++ auto PCHContainerOps = std::make_shared<PCHContainerOperations>(); ++ ++ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation( ++ CInvok, PCHContainerOps, Diags, FileMgr); ++ ++ if (!AST) ++ FAIL() << "failed to create ASTUnit"; ++ ++ EXPECT_FALSE(AST->getASTContext().getPrintingPolicy().UseVoidForZeroParams); ++ ++ llvm::SmallString<256> ASTFileName; ++ ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("ast-unit", "ast", FD, ASTFileName)); ++ tool_output_file ast_file(ASTFileName, FD); ++ AST->Save(ASTFileName.str()); ++ ++ EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName)); ++ ++ std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile( ++ ASTFileName.str(), PCHContainerOps->getRawReader(), ASTUnit::LoadEverything, Diags, ++ FileSystemOptions(), /*UseDebugInfo=*/false); ++ ++ if (!AU) ++ FAIL() << "failed to load ASTUnit"; ++ ++ EXPECT_FALSE(AU->getASTContext().getPrintingPolicy().UseVoidForZeroParams); ++} ++ ++} // anonymous namespace +diff --git a/tools/clang/unittests/Frontend/CMakeLists.txt b/tools/clang/unittests/Frontend/CMakeLists.txt +index 674f77bd01..4312151c04 100644 +--- a/tools/clang/unittests/Frontend/CMakeLists.txt ++++ b/tools/clang/unittests/Frontend/CMakeLists.txt +@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS + ) + + add_clang_unittest(FrontendTests ++ ASTUnitTest.cpp + FrontendActionTest.cpp + CodeGenActionTest.cpp + ) +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0009-libclang-Visit-attributes-for-function-and-class-tem.patch b/packages/llvm/llvm5-0009-libclang-Visit-attributes-for-function-and-class-tem.patch new file mode 100644 index 0000000000000000000000000000000000000000..d38d190db89771be6ee98ec92a0e3426a943f19e --- /dev/null +++ b/packages/llvm/llvm5-0009-libclang-Visit-attributes-for-function-and-class-tem.patch @@ -0,0 +1,97 @@ +From 2d3c0e5f3e3e6da701f3a5010a9700253deec16d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de> +Date: Fri, 21 Jul 2017 10:16:45 +0200 +Subject: [PATCH 09/12] [libclang] Visit attributes for function and class + templates + +--- + bindings/python/tests/cindex/test_cursor.py | 20 ++++++++++++++++++++ + test/Index/annotate-attribute.cpp | 12 ++++++++++++ + tools/libclang/CIndex.cpp | 6 ++++-- + 3 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/tools/clang/bindings/python/tests/cindex/test_cursor.py +index 2d50ec5901..863919e4c5 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -397,6 +397,26 @@ def test_annotation_attribute(): + else: + assert False, "Couldn't find annotation" + ++def test_annotation_template(): ++ annotation = '__attribute__ ((annotate("annotation")))' ++ for source, kind in [ ++ ('int foo (T value) %s;', CursorKind.FUNCTION_TEMPLATE), ++ ('class %s foo {};', CursorKind.CLASS_TEMPLATE), ++ ]: ++ source = 'template<typename T> ' + (source % annotation) ++ tu = get_tu(source, lang="cpp") ++ ++ foo = get_cursor(tu, 'foo') ++ assert foo is not None ++ assert foo.kind == kind ++ ++ for c in foo.get_children(): ++ if c.kind == CursorKind.ANNOTATE_ATTR: ++ assert c.displayname == "annotation" ++ break ++ else: ++ assert False, "Couldn't find annotation for {}".format(kind) ++ + def test_result_type(): + tu = get_tu('int foo();') + foo = get_cursor(tu, 'foo') +diff --git a/tools/clang/test/Index/annotate-attribute.cpp b/tools/clang/test/Index/annotate-attribute.cpp +index d822210e49..bf415fc8fe 100644 +--- a/tools/clang/test/Index/annotate-attribute.cpp ++++ b/tools/clang/test/Index/annotate-attribute.cpp +@@ -16,6 +16,12 @@ protected: + void methodWithoutAttribute(); + }; + ++template <typename T> ++class __attribute__((annotate("works"))) TemplateTest {}; ++ ++template <typename T> ++int templateFunction(T value) __attribute__((annotate("works"))); ++ + // CHECK: ClassDecl=Test:3:7 (Definition) Extent=[3:1 - 17:2] + // CHECK-NEXT: CXXAccessSpecifier=:4:1 (Definition) Extent=[4:1 - 4:8] + // CHECK-NEXT: CXXMethod=aMethod:5:51 Extent=[5:3 - 5:60] +@@ -31,3 +37,9 @@ protected: + // CHECK-NEXT: CompoundStmt= Extent=[12:23 - 12:25] + // CHECK-NEXT: CXXAccessSpecifier=:14:1 (Definition) Extent=[14:1 - 14:11] + // CHECK-NEXT: CXXMethod=methodWithoutAttribute:16:8 Extent=[16:3 - 16:32] ++// CHECK: ClassTemplate=TemplateTest:20:42 (Definition) Extent=[19:1 - 20:57] ++// CHECK-NEXT: TemplateTypeParameter=T:19:20 (Definition) Extent=[19:11 - 19:21] [access=public] ++// CHECK-NEXT: attribute(annotate)=works Extent=[20:22 - 20:39] ++// CHECK: FunctionTemplate=templateFunction:23:5 Extent=[22:1 - 23:65] ++// CHECK-NEXT: TemplateTypeParameter=T:22:20 (Definition) Extent=[22:11 - 22:21] [access=public] ++// CHECK-NEXT: attribute(annotate)=works Extent=[23:46 - 23:63] +diff --git a/tools/clang/tools/libclang/CIndex.cpp b/tools/clang/tools/libclang/CIndex.cpp +index 04fd775fb0..27f74b2aa2 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -907,7 +907,8 @@ bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + +- return VisitFunctionDecl(D->getTemplatedDecl()); ++ auto* FD = D->getTemplatedDecl(); ++ return VisitAttributes(FD) || VisitFunctionDecl(FD); + } + + bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { +@@ -916,7 +917,8 @@ bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + +- return VisitCXXRecordDecl(D->getTemplatedDecl()); ++ auto* CD = D->getTemplatedDecl(); ++ return VisitAttributes(CD) || VisitCXXRecordDecl(CD); + } + + bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0010-libclang-Add-support-for-querying-cursor-availabilit.patch b/packages/llvm/llvm5-0010-libclang-Add-support-for-querying-cursor-availabilit.patch new file mode 100644 index 0000000000000000000000000000000000000000..1119bc3b7090fd4d24356697ba86c1fdfc7fbf82 --- /dev/null +++ b/packages/llvm/llvm5-0010-libclang-Add-support-for-querying-cursor-availabilit.patch @@ -0,0 +1,123 @@ +From 3206e3ef840b1ca16346f2c925edc47c5a9697ad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de> +Date: Tue, 25 Jul 2017 15:49:14 +0200 +Subject: [PATCH 10/12] [libclang] Add support for querying cursor availability + +This patch allows checking the availability of cursors through libclang and clang.cindex (Python). +This e.g. allows to check whether a C++ member function has been marked as deleted. +--- + bindings/python/clang/cindex.py | 33 +++++++++++++++++++++++++++++ + bindings/python/tests/cindex/test_cursor.py | 25 ++++++++++++++++++++++ + 2 files changed, 58 insertions(+) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py +index a5bb58b44f..b21f2b75f2 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -1586,6 +1586,16 @@ class Cursor(Structure): + return StorageClass.from_id(self._storage_class) + + @property ++ def availability(self): ++ """ ++ Retrieves the availability of the entity pointed at by the cursor. ++ """ ++ if not hasattr(self, '_availability'): ++ self._availability = conf.lib.clang_getCursorAvailability(self) ++ ++ return AvailabilityKind.from_id(self._availability) ++ ++ @property + def access_specifier(self): + """ + Retrieves the access specifier (if any) of the entity pointed at by the +@@ -1925,6 +1935,24 @@ StorageClass.OPENCLWORKGROUPLOCAL = StorageClass(5) + StorageClass.AUTO = StorageClass(6) + StorageClass.REGISTER = StorageClass(7) + ++### Availability Kinds ### ++ ++class AvailabilityKind(BaseEnumeration): ++ """ ++ Describes the availability of an entity. ++ """ ++ ++ # The unique kind objects, indexed by id. ++ _kinds = [] ++ _name_map = None ++ ++ def __repr__(self): ++ return 'AvailabilityKind.%s' % (self.name,) ++ ++AvailabilityKind.AVAILABLE = AvailabilityKind(0) ++AvailabilityKind.DEPRECATED = AvailabilityKind(1) ++AvailabilityKind.NOT_AVAILABLE = AvailabilityKind(2) ++AvailabilityKind.NOT_ACCESSIBLE = AvailabilityKind(3) + + ### C++ access specifiers ### + +@@ -3472,6 +3500,10 @@ functionList = [ + [TranslationUnit, SourceLocation], + Cursor), + ++ ("clang_getCursorAvailability", ++ [Cursor], ++ c_int), ++ + ("clang_getCursorDefinition", + [Cursor], + Cursor, +@@ -4096,6 +4128,7 @@ conf = Config() + register_enumerations() + + __all__ = [ ++ 'AvailabilityKind', + 'Config', + 'CodeCompletionResults', + 'CompilationDatabase', +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/tools/clang/bindings/python/tests/cindex/test_cursor.py +index 863919e4c5..6c20577302 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -1,6 +1,7 @@ + import ctypes + import gc + ++from clang.cindex import AvailabilityKind + from clang.cindex import CursorKind + from clang.cindex import TemplateArgumentKind + from clang.cindex import TokenGroup +@@ -425,6 +426,30 @@ def test_result_type(): + t = foo.result_type + assert t.kind == TypeKind.INT + ++def test_availability(): ++ tu = get_tu('class A { A(A const&) = delete; };', lang='cpp') ++ ++ # AvailabilityKind.AVAILABLE ++ cursor = get_cursor(tu, 'A') ++ assert cursor.kind == CursorKind.CLASS_DECL ++ assert cursor.availability == AvailabilityKind.AVAILABLE ++ ++ # AvailabilityKind.NOT_AVAILABLE ++ cursors = get_cursors(tu, 'A') ++ for c in cursors: ++ if c.kind == CursorKind.CONSTRUCTOR: ++ assert c.availability == AvailabilityKind.NOT_AVAILABLE ++ break ++ else: ++ assert False, "Could not find cursor for deleted constructor" ++ ++ # AvailabilityKind.DEPRECATED ++ tu = get_tu('void test() __attribute__((deprecated));', lang='cpp') ++ cursor = get_cursor(tu, 'test') ++ assert cursor.availability == AvailabilityKind.DEPRECATED ++ ++ # AvailabilityKind.NOT_ACCESSIBLE is only used in the code completion results ++ + def test_get_tokens(): + """Ensure we can map cursors back to tokens.""" + tu = get_tu('int foo(int i);') +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0011-libclang-Allow-visiting-of-implicit-declarations-and.patch b/packages/llvm/llvm5-0011-libclang-Allow-visiting-of-implicit-declarations-and.patch new file mode 100644 index 0000000000000000000000000000000000000000..b9835bbd5060fde987f0b2ef0216e8f56e0de36f --- /dev/null +++ b/packages/llvm/llvm5-0011-libclang-Allow-visiting-of-implicit-declarations-and.patch @@ -0,0 +1,433 @@ +From c7701fe91022a116e0a37f410e70fe8906f56441 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 11/12] [libclang] Allow visiting of implicit declarations and + template instantiations (WIP!) + +--- + bindings/python/clang/cindex.py | 45 +++++++++-- + bindings/python/tests/cindex/test_cursor.py | 33 ++++++++ + include/clang-c/Index.h | 31 ++++++++ + tools/libclang/CIndex.cpp | 112 ++++++++++++++++++++++++++-- + tools/libclang/CursorVisitor.h | 12 ++- + tools/libclang/libclang.exports | 2 + + 6 files changed, 219 insertions(+), 16 deletions(-) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py +index b21f2b75f2..2416fd1803 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -1407,6 +1407,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 +@@ -1496,6 +1505,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 +@@ -1790,8 +1803,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): +@@ -1804,18 +1821,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): +@@ -3840,6 +3863,10 @@ functionList = [ + [Type], + bool), + ++ ("clang_isImplicit", ++ [Cursor], ++ bool), ++ + ("clang_isInvalid", + [CursorKind], + bool), +@@ -3903,6 +3930,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/tools/clang/bindings/python/tests/cindex/test_cursor.py +index 6c20577302..43606b605c 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -70,6 +70,39 @@ def test_get_children(): + assert tu_nodes[2].displayname == 'f0(int, int)' + assert 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()) ++ assert len(children) == 0 ++ ++ children = list(cursor.get_children(with_implicit=True)) ++ assert len(children) > 0 ++ for child in children: ++ assert child.is_implicit() ++ assert child.spelling == "X" ++ assert child.kind in [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') ++ assert cursor.kind == CursorKind.FUNCTION_TEMPLATE ++ ++ for child in cursor.get_children(): ++ # should not return an instantiation: ++ assert child.kind != CursorKind.FUNCTION_DECL ++ ++ for child in cursor.get_children(with_template_instantiations=True): ++ if child.kind == CursorKind.FUNCTION_DECL: ++ assert child.spelling == 'frobnicate' ++ break ++ else: ++ assert False, "Couldn't find template instantiation" ++ + def test_references(): + """Ensure that references to TranslationUnit are kept.""" + tu = get_tu('int x;') +diff --git a/tools/clang/include/clang-c/Index.h b/tools/clang/include/clang-c/Index.h +index 7fd17366ee..abe70e9566 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -2670,6 +2670,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); ++ + /** + * \brief Describe the linkage of the entity referred to by a cursor. + */ +@@ -3961,6 +3966,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/tools/clang/tools/libclang/CIndex.cpp +index 27f74b2aa2..f32611b8d7 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -192,10 +192,11 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { + assert(0 && "Invalid declaration cursor"); + 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; + } + +@@ -700,10 +701,13 @@ bool CursorVisitor::VisitTagDecl(TagDecl *D) { + + 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; + +@@ -712,6 +716,7 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl( + break; + + case TSK_ExplicitSpecialization: ++ // Always visit body of explicit specializations + ShouldVisitBody = true; + break; + } +@@ -908,7 +913,31 @@ bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + 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) { +@@ -918,7 +947,40 @@ bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { + return true; + + 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) { +@@ -4314,6 +4376,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(); +@@ -5402,6 +5482,22 @@ unsigned clang_isUnexposed(enum CXCursorKind K) { + } + } + ++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; + } +diff --git a/tools/clang/tools/libclang/CursorVisitor.h b/tools/clang/tools/libclang/CursorVisitor.h +index 82f251a348..c659e866ef 100644 +--- a/tools/clang/tools/libclang/CursorVisitor.h ++++ b/tools/clang/tools/libclang/CursorVisitor.h +@@ -96,6 +96,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; +@@ -147,7 +153,9 @@ 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), +@@ -155,6 +163,8 @@ public: + VisitIncludedEntities(VisitIncludedPreprocessingEntries), + RegionOfInterest(RegionOfInterest), + VisitDeclsOnly(VisitDeclsOnly), ++ VisitImplicitDeclarations(VisitImplicitDeclarations), ++ VisitTemplateInstantiations(VisitTemplateInstantiations), + DI_current(nullptr), FileDI_current(nullptr) + { + Parent.kind = CXCursor_NoDeclFound; +diff --git a/tools/clang/tools/libclang/libclang.exports b/tools/clang/tools/libclang/libclang.exports +index b8e3df23ef..59c46ae09e 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -291,6 +291,7 @@ clang_isDeclaration + clang_isExpression + clang_isFileMultipleIncludeGuarded + clang_isFunctionTypeVariadic ++clang_isImplicit + clang_isInvalid + clang_isPODType + clang_isPreprocessing +@@ -332,6 +333,7 @@ clang_CompileCommand_getNumArgs + clang_CompileCommand_getArg + clang_visitChildren + clang_visitChildrenWithBlock ++clang_visitChildrenWithOptions + clang_ModuleMapDescriptor_create + clang_ModuleMapDescriptor_dispose + clang_ModuleMapDescriptor_setFrameworkModuleName +-- +2.13.0 + diff --git a/packages/llvm/llvm5-0012-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch b/packages/llvm/llvm5-0012-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch new file mode 100644 index 0000000000000000000000000000000000000000..0be6629fff035d51a29441f2d5c45caecffe377c --- /dev/null +++ b/packages/llvm/llvm5-0012-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch @@ -0,0 +1,54 @@ +From 8566bbfaf8a34bf088cacf632b647922257d7d5f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Mon, 31 Jul 2017 14:09:52 +0200 +Subject: [PATCH 12/12] [libclang] WIP: Fix get_tokens in macro expansion + +--- + bindings/python/tests/cindex/test_cursor.py | 15 +++++++++++++++ + tools/libclang/CIndex.cpp | 4 ++-- + 2 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/tools/clang/bindings/python/tests/cindex/test_cursor.py +index 43606b605c..5c6f9fb320 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -523,6 +523,21 @@ def test_get_tokens_with_whitespace(): + assert ''.join(t.spelling for t in tokens) == source + assert len(tokens) == 27 + ++def test_get_tokens_in_macro(): ++ """regression test""" ++ source = "#define IMPL(name) struct name { name(int v = 0); }; \n IMPL(X)" ++ tu = get_tu(source, lang="cpp") ++ ctor = get_cursors(tu, "X")[1] ++ assert ctor.kind == CursorKind.CONSTRUCTOR ++ p = next(ctor.get_children()) ++ assert p.kind == CursorKind.PARM_DECL ++ children = list(p.get_children()) ++ assert len(children) == 1 ++ expr = children[0] ++ tokens = list(expr.get_tokens()) ++ assert len(tokens) == 1 ++ assert tokens[0].spelling == "0" ++ + def test_get_arguments(): + tu = get_tu('void foo(int i, int j);') + foo = get_cursor(tu, 'foo') +diff --git a/tools/clang/tools/libclang/CIndex.cpp b/tools/clang/tools/libclang/CIndex.cpp +index f32611b8d7..5849c7dfde 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -144,8 +144,8 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, + // We want the last character in this location, so we will adjust the + // location accordingly. + SourceLocation EndLoc = R.getEnd(); +- if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) +- EndLoc = SM.getExpansionRange(EndLoc).second; ++ // if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) ++ // EndLoc = SM.getExpansionRange(EndLoc).second; + if (R.isTokenRange() && EndLoc.isValid()) { + unsigned Length = Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc), + SM, LangOpts); +-- +2.13.0 + diff --git a/packages/llvm/llvm7-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch b/packages/llvm/llvm7-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch new file mode 100644 index 0000000000000000000000000000000000000000..eba3b7a7164106b0b6a6dc84b2dd3b5c08f5023f --- /dev/null +++ b/packages/llvm/llvm7-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch @@ -0,0 +1,77 @@ +From 5916da23627103563e38702de2d3bcff65d60406 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Wed, 26 Jul 2017 15:06:10 +0200 +Subject: [PATCH 1/5] [Tooling] Fully qualify template parameters of nested + name specifier in getFullyQualifiedName + +--- + tools/clang/lib/AST/QualTypeNames.cpp | 18 ++++++++++++++---- + tools/clang/unittests/Tooling/QualTypeNamesTest.cpp | 8 +++++++- + 2 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/tools/clang/lib/AST/QualTypeNames.cpp b/tools/clang/lib/AST/QualTypeNames.cpp +index 8b605ef295..8fcedccf48 100644 +--- a/tools/clang/lib/AST/QualTypeNames.cpp ++++ b/tools/clang/lib/AST/QualTypeNames.cpp +@@ -359,11 +359,21 @@ NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix) { ++ const Type *TypePtr = TD->getTypeForDecl(); ++ // In case of template specializations iterate over the arguments and ++ // fully qualify them as well. ++ if (isa<const TemplateSpecializationType>(TypePtr) || ++ isa<const RecordType>(TypePtr)) { ++ // We are asked to fully qualify and we have a Record Type (which ++ // may point to a template specialization) or Template ++ // Specialization Type. We need to fully qualify their arguments. ++ ++ TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); ++ } ++ + return NestedNameSpecifier::Create( +- Ctx, +- createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), +- false /*No TemplateKeyword*/, +- TD->getTypeForDecl()); ++ Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), ++ false /*No TemplateKeyword*/, TypePtr); + } + + /// Return the fully qualified type, including fully-qualified +diff --git a/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp b/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp +index b4c56f7bd5..e9ab495098 100644 +--- a/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp ++++ b/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp +@@ -67,6 +67,10 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + // Template parameter expansion. + Visitor.ExpectedQualTypeNames["CheckC"] = + "A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>"; ++ // Template parameters of nested name specifier should also be fully expanded. ++ Visitor.ExpectedQualTypeNames["CheckNested"] = ++ // "typename A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>::nested"; ++ "typename A::B::Template0<int, A::B::Class0>::nested"; + // Recursive template parameter expansion. + Visitor.ExpectedQualTypeNames["CheckD"] = + "A::B::Template0<A::B::Template1<A::B::C::MyInt, A::B::AnotherClass>, " +@@ -109,7 +113,7 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + " using InnerAlias = OuterTemplateClass<T>;\n" + " InnerAlias<int> AliasTypeVal;\n" + " }\n" +- " template<class X, class Y> class Template0;" ++ " template<class X, class Y> struct Template0 { typedef int nested; };" + " template<class X, class Y> class Template1;" + " typedef B::Class0 AnotherClass;\n" + " void Function1(Template0<C::MyInt,\n" +@@ -117,6 +121,8 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + " void Function2(Template0<Template1<C::MyInt, AnotherClass>,\n" + " Template0<int, long> > CheckD);\n" + " void Function3(const B::Class0* CheckM);\n" ++ " void Function4(typename Template0<C::MyInt,\n" ++ " AnotherClass>::nested CheckNested);\n" + " }\n" + "template<typename... Values> class Variadic {};\n" + "Variadic<int, B::Template0<int, char>, " +-- +2.18.0 + diff --git a/packages/llvm/llvm7-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch b/packages/llvm/llvm7-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec669b0dfdba49729c2b7f8ad6d4477211409169 --- /dev/null +++ b/packages/llvm/llvm7-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch @@ -0,0 +1,153 @@ +From 18b47d781d631667a40a543383cf2510968440e3 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). +--- + tools/clang/bindings/python/clang/cindex.py | 13 ++++++++++++ + tools/clang/bindings/python/tests/cindex/test_cursor.py | 8 ++++++++ + tools/clang/include/clang-c/Index.h | 8 ++++++++ + tools/clang/tools/libclang/CMakeLists.txt | 1 + + tools/clang/tools/libclang/CXType.cpp | 22 +++++++++++++++++++++ + tools/clang/tools/libclang/libclang.exports | 1 + + 6 files changed, 53 insertions(+) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py +index 56fcc78763..becf745040 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -2401,6 +2401,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 +@@ -3847,6 +3855,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 f5733fd158..26d5f01b23 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -311,6 +311,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 65dada38b0..a9bd6f4ebf 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -3318,6 +3318,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 e539c8308e..336a5c2e98 100644 +--- a/tools/clang/tools/libclang/CMakeLists.txt ++++ b/tools/clang/tools/libclang/CMakeLists.txt +@@ -41,6 +41,7 @@ set(LIBS + clangLex + clangSema + clangTooling ++ clangToolingCore + ) + + if (CLANG_ENABLE_ARCMT) +diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp +index 7c0f307944..9651c3a84a 100644 +--- a/tools/clang/tools/libclang/CXType.cpp ++++ b/tools/clang/tools/libclang/CXType.cpp +@@ -20,6 +20,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" +@@ -293,6 +294,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 95a42712c4..87773b9036 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -230,6 +230,7 @@ clang_getFileLocation + clang_getFileName + clang_getFileTime + clang_getFileUniqueID ++clang_getFullyQualifiedTypeName + clang_getFunctionTypeCallingConv + clang_getIBOutletCollectionType + clang_getIncludedFile +-- +2.18.0 + diff --git a/packages/llvm/llvm7-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch b/packages/llvm/llvm7-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch new file mode 100644 index 0000000000000000000000000000000000000000..e00f2c7d412443241994de6fcfeedfddbd881433 --- /dev/null +++ b/packages/llvm/llvm7-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch @@ -0,0 +1,261 @@ +From b0c94bdd15d06359177609cd204da718844bb4d8 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. +--- + bindings/python/clang/cindex.py | 31 +++++++++++++++----- + bindings/python/tests/cindex/test_cursor.py | 9 ++++++ + include/clang-c/Index.h | 32 +++++++++++++++++++-- + tools/libclang/CIndex.cpp | 15 ++++++++-- + tools/libclang/libclang.exports | 1 + + 5 files changed, 75 insertions(+), 13 deletions(-) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py +index becf745040..a43fcff150 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -515,6 +515,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 +@@ -524,7 +531,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 +@@ -533,8 +540,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) + +@@ -1834,13 +1841,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.""" +@@ -3058,18 +3068,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): + """ +@@ -3947,6 +3960,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/bindings/python/tests/cindex/test_cursor.py +index 26d5f01b23..d7ddf83130 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -5,6 +5,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 +@@ -483,6 +484,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/include/clang-c/Index.h +index a9bd6f4ebf..b77483f5a9 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 49 ++#define CINDEX_VERSION_MINOR 50 + + #define CINDEX_VERSION_ENCODE(major, minor) ( \ + ((major) * 10000) \ +@@ -4799,6 +4799,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. +@@ -4815,9 +4837,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/tools/libclang/CIndex.cpp +index 499d9abf9a..bbc29af346 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -6585,7 +6585,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()); +@@ -6607,6 +6607,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; +@@ -6680,7 +6683,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; +@@ -6694,6 +6697,12 @@ CXToken *clang_getToken(CXTranslationUnit TU, CXSourceLocation Location) { + + 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; + } +@@ -6719,7 +6728,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/tools/libclang/libclang.exports +index 87773b9036..d185e26a2e 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -327,6 +327,7 @@ clang_suspendTranslationUnit + clang_sortCodeCompletionResults + clang_toggleCrashRecovery + clang_tokenize ++clang_tokenizeRange + clang_CompilationDatabase_fromDirectory + clang_CompilationDatabase_dispose + clang_CompilationDatabase_getCompileCommands +-- +2.18.0 + diff --git a/packages/llvm/llvm7-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch b/packages/llvm/llvm7-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch new file mode 100644 index 0000000000000000000000000000000000000000..50cac737fd66ca1f2c1aefd6be4ad21fe3df2085 --- /dev/null +++ b/packages/llvm/llvm7-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch @@ -0,0 +1,433 @@ +From e11c5d12937f1483ab4b0b509ec4a11ba5789de0 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 + +--- + bindings/python/clang/cindex.py | 45 ++++++-- + bindings/python/tests/cindex/test_cursor.py | 33 ++++++ + include/clang-c/Index.h | 31 ++++++ + tools/libclang/CIndex.cpp | 112 ++++++++++++++++++-- + tools/libclang/CursorVisitor.h | 12 ++- + tools/libclang/libclang.exports | 2 + + 6 files changed, 219 insertions(+), 16 deletions(-) + +diff --git a/tools/clang/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py +index a43fcff150..027f2d7f71 100644 +--- a/tools/clang/bindings/python/clang/cindex.py ++++ b/tools/clang/bindings/python/clang/cindex.py +@@ -1408,6 +1408,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 +@@ -1497,6 +1506,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 +@@ -1813,8 +1826,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): +@@ -1827,18 +1844,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): +@@ -3905,6 +3928,10 @@ functionList = [ + [Type], + bool), + ++ ("clang_isImplicit", ++ [Cursor], ++ bool), ++ + ("clang_isInvalid", + [CursorKind], + bool), +@@ -3968,6 +3995,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/bindings/python/tests/cindex/test_cursor.py +index d7ddf83130..5a4eee4377 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -89,6 +89,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/include/clang-c/Index.h +index b77483f5a9..e5a47c0fca 100644 +--- a/tools/clang/include/clang-c/Index.h ++++ b/tools/clang/include/clang-c/Index.h +@@ -2725,6 +2725,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. + */ +@@ -4041,6 +4046,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/tools/libclang/CIndex.cpp +index bbc29af346..6e0a208d55 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -199,10 +199,11 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { + assert(0 && "Invalid declaration cursor"); + 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; + } + +@@ -707,10 +708,13 @@ bool CursorVisitor::VisitTagDecl(TagDecl *D) { + + 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; + +@@ -719,6 +723,7 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl( + break; + + case TSK_ExplicitSpecialization: ++ // Always visit body of explicit specializations + ShouldVisitBody = true; + break; + } +@@ -934,7 +939,31 @@ bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + 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) { +@@ -944,7 +973,40 @@ bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { + return true; + + 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) { +@@ -4391,6 +4453,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(); +@@ -5693,6 +5773,22 @@ unsigned clang_isUnexposed(enum CXCursorKind K) { + } + } + ++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; + } +diff --git a/tools/clang/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h +index f2fb68fab9..02085b1783 100644 +--- a/tools/clang/tools/libclang/CursorVisitor.h ++++ b/tools/clang/tools/libclang/CursorVisitor.h +@@ -96,6 +96,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; +@@ -147,7 +153,9 @@ 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), +@@ -155,6 +163,8 @@ public: + VisitIncludedEntities(VisitIncludedPreprocessingEntries), + RegionOfInterest(RegionOfInterest), + VisitDeclsOnly(VisitDeclsOnly), ++ VisitImplicitDeclarations(VisitImplicitDeclarations), ++ VisitTemplateInstantiations(VisitTemplateInstantiations), + DI_current(nullptr), FileDI_current(nullptr) + { + Parent.kind = CXCursor_NoDeclFound; +diff --git a/tools/clang/tools/libclang/libclang.exports b/tools/libclang/libclang.exports +index d185e26a2e..1376f29509 100644 +--- a/tools/clang/tools/libclang/libclang.exports ++++ b/tools/clang/tools/libclang/libclang.exports +@@ -302,6 +302,7 @@ clang_isInvalidDeclaration + clang_isExpression + clang_isFileMultipleIncludeGuarded + clang_isFunctionTypeVariadic ++clang_isImplicit + clang_isInvalid + clang_isPODType + clang_isPreprocessing +@@ -343,6 +344,7 @@ clang_CompileCommand_getNumArgs + clang_CompileCommand_getArg + clang_visitChildren + clang_visitChildrenWithBlock ++clang_visitChildrenWithOptions + clang_ModuleMapDescriptor_create + clang_ModuleMapDescriptor_dispose + clang_ModuleMapDescriptor_setFrameworkModuleName +-- +2.18.0 + diff --git a/packages/llvm/llvm7-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch b/packages/llvm/llvm7-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch new file mode 100644 index 0000000000000000000000000000000000000000..e71fd2ccac0d55465b2f870e31d245f49843264d --- /dev/null +++ b/packages/llvm/llvm7-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch @@ -0,0 +1,52 @@ +From 40ddcbc8dd69324bb4c97fd808924c5ee967f3d5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Mon, 31 Jul 2017 14:09:52 +0200 +Subject: [PATCH 5/5] [libclang] WIP: Fix get_tokens in macro expansion + +--- + bindings/python/tests/cindex/test_cursor.py | 15 +++++++++++++++ + tools/libclang/CIndex.cpp | 2 +- + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py +index 5a4eee4377..a275d6b8cf 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -547,6 +547,21 @@ class TestCursor(unittest.TestCase): + r_cursor = t_cursor.referenced # should not raise an exception + self.assertEqual(r_cursor.kind, CursorKind.CLASS_DECL) + ++ def test_get_tokens_in_macro_expansion(self): ++ """regression test""" ++ source = "#define IMPL(name) struct name { name(int v = 123); }; \n IMPL(X)" ++ tu = get_tu(source, lang="cpp") ++ ctor = get_cursors(tu, "X")[1] ++ self.assertEqual(ctor.kind, CursorKind.CONSTRUCTOR) ++ p = next(ctor.get_children()) ++ self.assertEqual(p.kind, CursorKind.PARM_DECL, (p.kind, p.spelling)) ++ children = list(p.get_children()) ++ self.assertEqual(len(children), 1, [(c.kind, c.spelling) for c in children]) ++ expr = children[0] ++ tokens = list(expr.get_tokens()) ++ self.assertEqual(len(tokens), 1, [t.spelling for t in tokens]) ++ self.assertEqual(tokens[0].spelling, "123") ++ + def test_get_arguments(self): + tu = get_tu('void foo(int i, int j);') + foo = get_cursor(tu, 'foo') +diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp +index 6e0a208d55..2ba96653ff 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -148,7 +148,7 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, + // location accordingly. + SourceLocation EndLoc = R.getEnd(); + bool IsTokenRange = R.isTokenRange(); +- if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) { ++ if (false /*FIXME*/ && EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) { + CharSourceRange Expansion = SM.getExpansionRange(EndLoc); + EndLoc = Expansion.getEnd(); + IsTokenRange = Expansion.isTokenRange(); +-- +2.18.0 + diff --git a/packages/llvm/llvm7_intel.patch b/packages/llvm/llvm7_intel.patch new file mode 100644 index 0000000000000000000000000000000000000000..710545a619d263c3cc5f3d30bd3e891a8853b7de --- /dev/null +++ b/packages/llvm/llvm7_intel.patch @@ -0,0 +1,50 @@ +diff --git a/llvm/include/llvm/ADT/StringExtras.h b/llvm/include/llvm/ADT/StringExtras.h +index 71b0e7527cb..3304a378f37 100644 +--- a/llvm/include/llvm/ADT/StringExtras.h ++++ b/llvm/include/llvm/ADT/StringExtras.h +@@ -369,7 +369,7 @@ inline size_t join_items_size(const A1 &A, Args &&... Items) { + template <typename IteratorT> + inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) { + using tag = typename std::iterator_traits<IteratorT>::iterator_category; +- return detail::join_impl(Begin, End, Separator, tag()); ++ return llvm::detail::join_impl(Begin, End, Separator, tag()); + } + + /// Joins the strings in the range [R.begin(), R.end()), adding Separator +diff --git a/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h b/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h +index 25b2efd33c9..40144d96044 100644 +--- a/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h ++++ b/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h +@@ -186,8 +186,9 @@ public: + /// topological sort) and it's class is the same regardless of block type. + struct BlockNode { + using IndexType = uint32_t; ++ using IndexTypeLimits = std::numeric_limits<IndexType>; + +- IndexType Index = std::numeric_limits<uint32_t>::max(); ++ IndexType Index = IndexTypeLimits::max(); + + BlockNode() = default; + BlockNode(IndexType Index) : Index(Index) {} +diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp +index 4325d57f73d..96e1e1d5503 100644 +--- a/llvm/lib/ExecutionEngine/Orc/Core.cpp ++++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp +@@ -1423,7 +1423,7 @@ VSO::lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, + if (SymI->second.getAddress() != 0) { + Q->resolve(Name, SymI->second); + if (Q->isFullyResolved()) +- ActionFlags |= NotifyFullyResolved; ++ ActionFlags = static_cast<LookupImplActionFlags>(ActionFlags | NotifyFullyResolved); + } + + // If the symbol is lazy, get the MaterialiaztionUnit for it. +@@ -1456,7 +1456,7 @@ VSO::lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, + // continue. + Q->notifySymbolReady(); + if (Q->isFullyReady()) +- ActionFlags |= NotifyFullyReady; ++ ActionFlags = static_cast<LookupImplActionFlags>(ActionFlags | NotifyFullyReady); + continue; + } + diff --git a/packages/llvm/llvm9-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch b/packages/llvm/llvm9-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch new file mode 100644 index 0000000000000000000000000000000000000000..e03dd4cf36c098fda1a23ff713d1b4dd5f1e38e3 --- /dev/null +++ b/packages/llvm/llvm9-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch @@ -0,0 +1,77 @@ +From 33d7d68cb694613dfa836cf506d8af012563b9c2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Wed, 26 Jul 2017 15:06:10 +0200 +Subject: [PATCH 1/5] [Tooling] Fully qualify template parameters of nested + name specifier in getFullyQualifiedName + +--- + clang/lib/AST/QualTypeNames.cpp | 18 ++++++++++++++---- + clang/unittests/Tooling/QualTypeNamesTest.cpp | 8 +++++++- + 2 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/tools/clang/lib/AST/QualTypeNames.cpp b/tools/clang/lib/AST/QualTypeNames.cpp +index f28f00171cc..ecfef57566e 100644 +--- a/tools/clang/lib/AST/QualTypeNames.cpp ++++ b/tools/clang/lib/AST/QualTypeNames.cpp +@@ -356,11 +356,21 @@ NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix) { ++ const Type *TypePtr = TD->getTypeForDecl(); ++ // In case of template specializations iterate over the arguments and ++ // fully qualify them as well. ++ if (isa<const TemplateSpecializationType>(TypePtr) || ++ isa<const RecordType>(TypePtr)) { ++ // We are asked to fully qualify and we have a Record Type (which ++ // may point to a template specialization) or Template ++ // Specialization Type. We need to fully qualify their arguments. ++ ++ TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); ++ } ++ + return NestedNameSpecifier::Create( +- Ctx, +- createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), +- false /*No TemplateKeyword*/, +- TD->getTypeForDecl()); ++ Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), ++ false /*No TemplateKeyword*/, TypePtr); + } + + /// Return the fully qualified type, including fully-qualified +diff --git a/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp b/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp +index b6c30297787..e93a0475812 100644 +--- a/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp ++++ b/tools/clang/unittests/Tooling/QualTypeNamesTest.cpp +@@ -66,6 +66,10 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + // Template parameter expansion. + Visitor.ExpectedQualTypeNames["CheckC"] = + "A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>"; ++ // Template parameters of nested name specifier should also be fully expanded. ++ Visitor.ExpectedQualTypeNames["CheckNested"] = ++ // "typename A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>::nested"; ++ "typename A::B::Template0<int, A::B::Class0>::nested"; + // Recursive template parameter expansion. + Visitor.ExpectedQualTypeNames["CheckD"] = + "A::B::Template0<A::B::Template1<A::B::C::MyInt, A::B::AnotherClass>, " +@@ -108,7 +112,7 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + " using InnerAlias = OuterTemplateClass<T>;\n" + " InnerAlias<int> AliasTypeVal;\n" + " }\n" +- " template<class X, class Y> class Template0;" ++ " template<class X, class Y> struct Template0 { typedef int nested; };" + " template<class X, class Y> class Template1;" + " typedef B::Class0 AnotherClass;\n" + " void Function1(Template0<C::MyInt,\n" +@@ -116,6 +120,8 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { + " void Function2(Template0<Template1<C::MyInt, AnotherClass>,\n" + " Template0<int, long> > CheckD);\n" + " void Function3(const B::Class0* CheckM);\n" ++ " void Function4(typename Template0<C::MyInt,\n" ++ " AnotherClass>::nested CheckNested);\n" + " }\n" + "template<typename... Values> class Variadic {};\n" + "Variadic<int, B::Template0<int, char>, " +-- +2.23.0 + diff --git a/packages/llvm/llvm9-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch b/packages/llvm/llvm9-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch new file mode 100644 index 0000000000000000000000000000000000000000..b1da65b18e22bc2f7052a4ed269cab6a9db2a8d7 --- /dev/null +++ b/packages/llvm/llvm9-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 59 ++#define CINDEX_VERSION_MINOR 60 + + #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/llvm9-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch b/packages/llvm/llvm9-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch new file mode 100644 index 0000000000000000000000000000000000000000..e3a0012bd24da636ed172ae308242c2cadb547ae --- /dev/null +++ b/packages/llvm/llvm9-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 60 ++#define CINDEX_VERSION_MINOR 61 + + #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; +@@ -6779,6 +6782,12 @@ CXToken *clang_getToken(CXTranslationUnit TU, CXSourceLocation Location) { + + 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; + } +@@ -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/llvm9-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch b/packages/llvm/llvm9-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef4a125e82d6b42b73574ce10ced78aa2d597590 --- /dev/null +++ b/packages/llvm/llvm9-0004-libclang-WIP-Allow-visiting-of-implicit-declarations.patch @@ -0,0 +1,442 @@ +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 61 ++#define CINDEX_VERSION_MINOR 62 + + #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 +@@ -195,10 +195,11 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { + assert(0 && "Invalid declaration cursor"); + 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; + } + +@@ -703,10 +704,13 @@ bool CursorVisitor::VisitTagDecl(TagDecl *D) { + + 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; + } +@@ -930,7 +935,31 @@ bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + 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) { +@@ -940,7 +969,40 @@ bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { + return true; + + 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(); +@@ -5774,6 +5854,22 @@ unsigned clang_isUnexposed(enum CXCursorKind K) { + } + } + ++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; + } +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; +@@ -146,7 +152,9 @@ 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), +@@ -154,6 +162,8 @@ public: + VisitIncludedEntities(VisitIncludedPreprocessingEntries), + RegionOfInterest(RegionOfInterest), + VisitDeclsOnly(VisitDeclsOnly), ++ VisitImplicitDeclarations(VisitImplicitDeclarations), ++ VisitTemplateInstantiations(VisitTemplateInstantiations), + DI_current(nullptr), FileDI_current(nullptr) + { + Parent.kind = CXCursor_NoDeclFound; +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/llvm9-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch b/packages/llvm/llvm9-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch new file mode 100644 index 0000000000000000000000000000000000000000..68c83bce65c3253dd3653c102f417df67bd51300 --- /dev/null +++ b/packages/llvm/llvm9-0005-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch @@ -0,0 +1,52 @@ +From 0fa84bbd8c6f8eb8eb6a3bc30e4efe3f2cf4c283 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <johann.klaehn@kip.uni-heidelberg.de> +Date: Mon, 31 Jul 2017 14:09:52 +0200 +Subject: [PATCH 5/5] [libclang] WIP: Fix get_tokens in macro expansion + +--- + clang/bindings/python/tests/cindex/test_cursor.py | 15 +++++++++++++++ + clang/tools/libclang/CIndex.cpp | 2 +- + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py +index d061f37c25c..38702df74f2 100644 +--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py ++++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py +@@ -552,6 +552,21 @@ class TestCursor(unittest.TestCase): + r_cursor = t_cursor.referenced # should not raise an exception + self.assertEqual(r_cursor.kind, CursorKind.CLASS_DECL) + ++ def test_get_tokens_in_macro_expansion(self): ++ """regression test""" ++ source = "#define IMPL(name) struct name { name(int v = 123); }; \n IMPL(X)" ++ tu = get_tu(source, lang="cpp") ++ ctor = get_cursors(tu, "X")[1] ++ self.assertEqual(ctor.kind, CursorKind.CONSTRUCTOR) ++ p = next(ctor.get_children()) ++ self.assertEqual(p.kind, CursorKind.PARM_DECL, (p.kind, p.spelling)) ++ children = list(p.get_children()) ++ self.assertEqual(len(children), 1, [(c.kind, c.spelling) for c in children]) ++ expr = children[0] ++ tokens = list(expr.get_tokens()) ++ self.assertEqual(len(tokens), 1, [t.spelling for t in tokens]) ++ self.assertEqual(tokens[0].spelling, "123") ++ + def test_get_arguments(self): + tu = get_tu('void foo(int i, int j);') + foo = get_cursor(tu, 'foo') +diff --git a/tools/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp +index 7ee6b704647..e4b95436704 100644 +--- a/tools/clang/tools/libclang/CIndex.cpp ++++ b/tools/clang/tools/libclang/CIndex.cpp +@@ -145,7 +145,7 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, + // location accordingly. + SourceLocation EndLoc = R.getEnd(); + bool IsTokenRange = R.isTokenRange(); +- if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) { ++ if (false /*FIXME*/ && EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) { + CharSourceRange Expansion = SM.getExpansionRange(EndLoc); + EndLoc = Expansion.getEnd(); + IsTokenRange = Expansion.isTokenRange(); +-- +2.23.0 + diff --git a/packages/llvm/llvm_gcc7.patch b/packages/llvm/llvm_gcc7.patch new file mode 100644 index 0000000000000000000000000000000000000000..c6d9d33a08aedffa2d3077f0384d1bec6547623e --- /dev/null +++ b/packages/llvm/llvm_gcc7.patch @@ -0,0 +1,10 @@ +--- a/lldb/include/lldb/Utility/TaskPool.h 2016-09-06 16:57:50.000000000 -0400 ++++ b/lldb/include/lldb/Utility/TaskPool.h 2017-08-29 16:29:41.448584015 -0400 +@@ -28,6 +28,7 @@ + + #include <cassert> + #include <cstdint> ++#include <functional> + #include <future> + #include <list> + #include <queue> diff --git a/packages/llvm/llvm_py37.patch b/packages/llvm/llvm_py37.patch new file mode 100644 index 0000000000000000000000000000000000000000..478be87994b9363a05c5b876780cd6379017e5d6 --- /dev/null +++ b/packages/llvm/llvm_py37.patch @@ -0,0 +1,37 @@ +From ecdefed7f6ba11421fe1ecc6c13a135ab7bcda73 Mon Sep 17 00:00:00 2001 +From: Pavel Labath <labath@google.com> +Date: Mon, 23 Jul 2018 11:37:36 +0100 +Subject: [PATCH] Fix PythonString::GetString for >=python-3.7 + +The return value of PyUnicode_AsUTF8AndSize is now "const char *". +--- + .../Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +index 6a9d57d5a..94f16b2c7 100644 +--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp ++++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +@@ -404,14 +404,16 @@ llvm::StringRef PythonString::GetString() const { + return llvm::StringRef(); + + Py_ssize_t size; +- char *c; ++ const char *data; + + #if PY_MAJOR_VERSION >= 3 +- c = PyUnicode_AsUTF8AndSize(m_py_obj, &size); ++ data = PyUnicode_AsUTF8AndSize(m_py_obj, &size); + #else ++ char *c; + PyString_AsStringAndSize(m_py_obj, &c, &size); ++ data = c; + #endif +- return llvm::StringRef(c, size); ++ return llvm::StringRef(data, size); + } + + size_t PythonString::GetSize() const { +-- +2.18.0.233.g985f88cf7e-goog + diff --git a/packages/llvm/llvm_python_path.patch b/packages/llvm/llvm_python_path.patch new file mode 100644 index 0000000000000000000000000000000000000000..9f821cc3654ac5dd8e0f2412ffd1a3209d844b5a --- /dev/null +++ b/packages/llvm/llvm_python_path.patch @@ -0,0 +1,14 @@ +diff --git a/compiler-rt/cmake/Modules/AddCompilerRT.cmake b/compiler-rt/cmake/Modules/AddCompilerRT.cmake +index dab55707338..6f4c6791141 100644 +--- a/compiler-rt/cmake/Modules/AddCompilerRT.cmake ++++ b/compiler-rt/cmake/Modules/AddCompilerRT.cmake +@@ -612,6 +612,9 @@ macro(add_custom_libcxx name prefix) + CMAKE_OBJDUMP + CMAKE_STRIP + CMAKE_SYSROOT ++ PYTHON_EXECUTABLE ++ Python3_EXECUTABLE ++ Python2_EXECUTABLE + CMAKE_SYSTEM_NAME) + foreach(variable ${PASSTHROUGH_VARIABLES}) + get_property(is_value_set CACHE ${variable} PROPERTY VALUE SET) diff --git a/packages/llvm/package.py b/packages/llvm/package.py new file mode 100644 index 0000000000000000000000000000000000000000..9649b55746c959849df6fb0aafd1610d0c4e6a93 --- /dev/null +++ b/packages/llvm/package.py @@ -0,0 +1,693 @@ +# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other +# Spack Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path +import re +import sys + +import llnl.util.tty as tty + +import spack.util.executable + + +class Llvm(CMakePackage, CudaPackage): + """The LLVM Project is a collection of modular and reusable compiler and + toolchain technologies. Despite its name, LLVM has little to do + with traditional virtual machines, though it does provide helpful + libraries that can be used to build them. The name "LLVM" itself + is not an acronym; it is the full name of the project. + """ + + homepage = "http://llvm.org/" + url = "https://github.com/llvm/llvm-project/archive/llvmorg-7.1.0.tar.gz" + list_url = "http://releases.llvm.org/download.html" + git = "https://github.com/llvm/llvm-project" + maintainers = ['trws', 'naromero77'] + + family = "compiler" # Used by lmod + + # fmt: off + version('main', branch='main') + version('12.0.1', sha256='66b64aa301244975a4aea489f402f205cde2f53dd722dad9e7b77a0459b4c8df') + version('12.0.0', sha256='8e6c99e482bb16a450165176c2d881804976a2d770e0445af4375e78a1fbf19c') + version('11.1.0', sha256='53a0719f3f4b0388013cfffd7b10c7d5682eece1929a9553c722348d1f866e79') + version('11.0.1', sha256='9c7ad8e8ec77c5bde8eb4afa105a318fd1ded7dff3747d14f012758719d7171b') + version('11.0.0', sha256='8ad4ddbafac4f2c8f2ea523c2c4196f940e8e16f9e635210537582a48622a5d5') + version('10.0.1', sha256='c7ccb735c37b4ec470f66a6c35fbae4f029c0f88038f6977180b1a8ddc255637') + version('10.0.0', sha256='b81c96d2f8f40dc61b14a167513d87c0d813aae0251e06e11ae8a4384ca15451') + version('9.0.1', sha256='be7b034641a5fda51ffca7f5d840b1a768737779f75f7c4fd18fe2d37820289a') + version('9.0.0', sha256='7807fac25330e24e9955ca46cd855dd34bbc9cc4fdba8322366206654d1036f2') + version('8.0.1', sha256='5b18f6111c7aee7c0933c355877d4abcfe6cb40c1a64178f28821849c725c841') + version('8.0.0', sha256='d81238b4a69e93e29f74ce56f8107cbfcf0c7d7b40510b7879e98cc031e25167') + version('7.1.0', sha256='71c93979f20e01f1a1cc839a247945f556fa5e63abf2084e8468b238080fd839') + version('7.0.1', sha256='f17a6cd401e8fd8f811fbfbb36dcb4f455f898c9d03af4044807ad005df9f3c0') + version('6.0.1', sha256='aefadceb231f4c195fe6d6cd3b1a010b269c8a22410f339b5a089c2e902aa177') + version('6.0.0', sha256='1946ec629c88d30122afa072d3c6a89cc5d5e4e2bb28dc63b2f9ebcc7917ee64') + version('5.0.2', sha256='fe87aa11558c08856739bfd9bd971263a28657663cb0c3a0af01b94f03b0b795') + version('5.0.1', sha256='84ca454abf262579814a2a2b846569f6e0cb3e16dc33ca3642b4f1dff6fbafd3') + version('5.0.0', sha256='1f1843315657a4371d8ca37f01265fa9aae17dbcf46d2d0a95c1fdb3c6a4bab6') + version('4.0.1', sha256='cd664fb3eec3208c08fb61189c00c9118c290b3be5adb3215a97b24255618be5') + version('4.0.0', sha256='28ca4b2fc434cb1f558e8865386c233c2a6134437249b8b3765ae745ffa56a34') + version('3.9.1', sha256='f5b6922a5c65f9232f83d89831191f2c3ccf4f41fdd8c63e6645bbf578c4ab92') + version('3.9.0', sha256='9c6563a72c8b5b79941c773937d997dd2b1b5b3f640136d02719ec19f35e0333') + version('3.8.1', sha256='69360f0648fde0dc3d3c4b339624613f3bc2a89c4858933bc3871a250ad02826') + version('3.8.0', sha256='b5cc5974cc2fd4e9e49e1bbd0700f872501a8678bd9694fa2b36c65c026df1d1') + version('3.7.1', sha256='d2cb0eb9b8eb21e07605bfe5e7a5c6c5f5f8c2efdac01ec1da6ffacaabe4195a') + version('3.7.0', sha256='dc00bc230be2006fb87b84f6fe4800ca28bc98e6692811a98195da53c9cb28c6') + version('3.6.2', sha256='f75d703a388ba01d607f9cf96180863a5e4a106827ade17b221d43e6db20778a') + version('3.5.1', sha256='5d739684170d5b2b304e4fb521532d5c8281492f71e1a8568187bfa38eb5909d') + # fmt: on + + # NOTE: The debug version of LLVM is an order of magnitude larger than + # the release version, and may take up 20-30 GB of space. If you want + # to save space, build with `build_type=Release`. + + variant( + "clang", + default=True, + description="Build the LLVM C/C++/Objective-C compiler frontend", + ) + variant( + "flang", + default=False, + description="Build the LLVM Fortran compiler frontend " + "(experimental - parser only, needs GCC)", + ) + variant( + "omp_debug", + default=False, + description="Include debugging code in OpenMP runtime libraries", + ) + variant("lldb", default=True, description="Build the LLVM debugger") + variant("lld", default=True, description="Build the LLVM linker") + variant("mlir", default=False, description="Build with MLIR support") + variant( + "internal_unwind", + default=True, + description="Build the libcxxabi libunwind", + ) + variant( + "polly", + default=True, + description="Build the LLVM polyhedral optimization plugin, " + "only builds for 3.7.0+", + ) + variant( + "libcxx", + default=True, + description="Build the LLVM C++ standard library", + ) + variant( + "compiler-rt", + default=True, + description="Build LLVM compiler runtime, including sanitizers", + ) + variant( + "gold", + default=(sys.platform != "darwin"), + description="Add support for LTO with the gold linker plugin", + ) + variant( + "split_dwarf", + default=False, + description="Build with split dwarf information", + ) + variant( + "shared_libs", + default=False, + description="Build all components as shared libraries, faster, " + "less memory to build, less stable", + ) + variant( + "llvm_dylib", + default=False, + description="Build LLVM shared library, containing all " + "components in a single shared library", + ) + variant( + "all_targets", + default=False, + description="Build all supported targets, default targets " + "<current arch>,NVPTX,AMDGPU,CppBackend", + ) + variant( + "build_type", + default="Release", + description="CMake build type", + values=("Debug", "Release", "RelWithDebInfo", "MinSizeRel"), + ) + variant( + "omp_tsan", + default=False, + description="Build with OpenMP capable thread sanitizer", + ) + variant('code_signing', default=False, + description="Enable code-signing on macOS") + variant("python", default=False, description="Install python bindings") + + extends("python", when="+python") + + variant('visionary', default=False, + description="Include patches necessary for visionary python " + "bindings generator") + variant('force_full_view', default=False, + description='Force linking of all files into view, including ' + 'known conflicts (e.g. libgomp).') + + patch('llvm5-0001-libclang-Add-support-for-checking-abstractness-of-re.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0002-libclang-Keep-track-of-TranslationUnit-instance-when.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0003-Fix-warnings-in-Tooling-QualTypeNamesTest.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0004-Defer-addition-of-keywords-to-identifier-table-when-.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0005-Tooling-Fully-qualify-template-parameters-of-nested-.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0006-libclang-Add-support-for-obtaining-fully-qualified-n.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0007-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0008-Fix-printing-policy-for-AST-context-loaded-from-file.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0009-libclang-Visit-attributes-for-function-and-class-tem.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0010-libclang-Add-support-for-querying-cursor-availabilit.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0011-libclang-Allow-visiting-of-implicit-declarations-and.patch', when='@5.0:6.999 +visionary', level=2) + patch('llvm5-0012-libclang-WIP-Fix-get_tokens-in-macro-expansion.patch', when='@5.0:6.999 +visionary', level=2) + + patch('llvm7-0001-Tooling-Fully-qualify-template-parameters-of-nested-.patch', when='@7.0:7.999 +visionary', level=2) + patch('llvm7-0002-libclang-Add-support-for-obtaining-fully-qualified-n.patch', when='@7.0:7.999 +visionary', level=2) + patch('llvm7-0003-libclang-Add-option-to-keep-whitespace-when-tokenizi.patch', when='@7.0:7.999 +visionary', level=2) + 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-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) + + # Build dependency + depends_on("cmake@3.4.3:", type="build") + depends_on("python@2.7:2.8", when="@:4.999 ~python", type="build") + depends_on("python", when="@5: ~python", type="build") + depends_on("pkgconfig", type="build") + + # Universal dependency + depends_on("python@2.7:2.8", when="@:4.999+python") + depends_on("python", when="@5:+python") + depends_on("z3", when="@9:") + + # openmp dependencies + depends_on("perl-data-dumper", type=("build")) + depends_on("hwloc") + depends_on("libelf", when="+cuda") # libomptarget + depends_on("libffi", when="+cuda") # libomptarget + + # ncurses dependency + depends_on("ncurses+termlib") + + # lldb dependencies + depends_on("swig", when="+lldb") + depends_on("libedit", when="+lldb") + depends_on("py-six", when="@5.0.0: +lldb +python") + + # gold support, required for some features + depends_on("binutils+gold+ld+plugins", when="+gold") + + # polly plugin + depends_on("gmp", when="@:3.6.999 +polly") + depends_on("isl", when="@:3.6.999 +polly") + + conflicts("+llvm_dylib", when="+shared_libs") + conflicts("+lldb", when="~clang") + conflicts("+libcxx", when="~clang") + conflicts("+internal_unwind", when="~clang") + conflicts("+compiler-rt", when="~clang") + conflicts("+flang", when="~clang") + # Introduced in version 11 as a part of LLVM and not a separate package. + conflicts("+flang", when="@:10.999") + + # Older LLVM do not build with newer GCC + conflicts("%gcc@11:", when="@:7") + conflicts("%gcc@8:", when="@:5") + conflicts("%gcc@:5.0.999", when="@8:") + + # OMP TSAN exists in > 5.x + conflicts("+omp_tsan", when="@:5.99") + + # cuda_arch value must be specified + conflicts("cuda_arch=none", when="+cuda", msg="A value for cuda_arch must be specified.") + + # MLIR exists in > 10.x + conflicts("+mlir", when="@:9") + + # code signing is only necessary on macOS", + conflicts('+code_signing', when='platform=linux') + conflicts('+code_signing', when='platform=cray') + + conflicts( + '+code_signing', + when='~lldb platform=darwin', + msg="code signing is only necessary for building the " + "in-tree debug server on macOS. Turning this variant " + "off enables a build of llvm with lldb that uses the " + "system debug server", + ) + + # LLVM bug https://bugs.llvm.org/show_bug.cgi?id=48234 + # CMake bug: https://gitlab.kitware.com/cmake/cmake/-/issues/21469 + # Fixed in upstream versions of both + conflicts('^cmake@3.19.0', when='@6.0.0:11.0.0') + + # Github issue #4986 + patch("llvm_gcc7.patch", when="@4.0.0:4.0.1+lldb %gcc@7.0:") + + # https://github.com/spack/spack/issues/24270 + patch('https://src.fedoraproject.org/rpms/llvm10/raw/7ce7ebd066955ea95ba2b491c41fbc6e4ee0643a/f/llvm10-gcc11.patch', + sha256='958c64838c9d469be514eef195eca0f8c3ab069bc4b64a48fad59991c626bab8', + when='@8:10 %gcc@11:') + + # Backport from llvm master + additional fix + # see https://bugs.llvm.org/show_bug.cgi?id=39696 + # for a bug report about this problem in llvm master. + patch("constexpr_longdouble.patch", when="@6:8+libcxx") + patch("constexpr_longdouble_9.0.patch", when="@9:10.0.0+libcxx") + + # Backport from llvm master; see + # https://bugs.llvm.org/show_bug.cgi?id=38233 + # for a bug report about this problem in llvm master. + patch("llvm_py37.patch", when="@4:6 ^python@3.7:") + + # https://bugs.llvm.org/show_bug.cgi?id=39696 + patch("thread-p9.patch", when="@develop+libcxx") + + # https://github.com/spack/spack/issues/19625, + # merged in llvm-11.0.0_rc2, but not found in 11.0.1 + patch("lldb_external_ncurses-10.patch", when="@10.0.0:11.0.1+lldb") + + # https://github.com/spack/spack/issues/19908 + # merged in llvm main prior to 12.0.0 + patch("llvm_python_path.patch", when="@11.0.0") + + # Workaround for issue https://github.com/spack/spack/issues/18197 + patch('llvm7_intel.patch', when='@7 %intel@18.0.2,19.0.4') + + # The functions and attributes below implement external package + # detection for LLVM. See: + # + # https://spack.readthedocs.io/en/latest/packaging_guide.html#making-a-package-discoverable-with-spack-external-find + executables = ['clang', 'flang', 'ld.lld', 'lldb'] + + @classmethod + def filter_detected_exes(cls, prefix, exes_in_prefix): + result = [] + for exe in exes_in_prefix: + # Executables like lldb-vscode-X are daemon listening + # on some port and would hang Spack during detection. + # clang-cl and clang-cpp are dev tools that we don't + # need to test + if any(x in exe for x in ('vscode', 'cpp', '-cl', '-gpu')): + continue + result.append(exe) + return result + + @classmethod + def determine_version(cls, exe): + version_regex = re.compile( + # Normal clang compiler versions are left as-is + r'clang version ([^ )\n]+)-svn[~.\w\d-]*|' + # Don't include hyphenated patch numbers in the version + # (see https://github.com/spack/spack/pull/14365 for details) + r'clang version ([^ )\n]+?)-[~.\w\d-]*|' + r'clang version ([^ )\n]+)|' + # LLDB + r'lldb version ([^ )\n]+)|' + # LLD + r'LLD ([^ )\n]+) \(compatible with GNU linkers\)' + ) + try: + compiler = Executable(exe) + output = compiler('--version', output=str, error=str) + if 'Apple' in output: + return None + match = version_regex.search(output) + if match: + return match.group(match.lastindex) + except spack.util.executable.ProcessError: + pass + except Exception as e: + tty.debug(e) + + return None + + @classmethod + def determine_variants(cls, exes, version_str): + variants, compilers = ['+clang'], {} + lld_found, lldb_found = False, False + for exe in exes: + if 'clang++' in exe: + compilers['cxx'] = exe + elif 'clang' in exe: + compilers['c'] = exe + elif 'flang' in exe: + variants.append('+flang') + compilers['fc'] = exe + compilers['f77'] = exe + elif 'ld.lld' in exe: + lld_found = True + compilers['ld'] = exe + elif 'lldb' in exe: + lldb_found = True + compilers['lldb'] = exe + + variants.append('+lld' if lld_found else '~lld') + variants.append('+lldb' if lldb_found else '~lldb') + + return ''.join(variants), {'compilers': compilers} + + @classmethod + def validate_detected_spec(cls, spec, extra_attributes): + # For LLVM 'compilers' is a mandatory attribute + msg = ('the extra attribute "compilers" must be set for ' + 'the detected spec "{0}"'.format(spec)) + assert 'compilers' in extra_attributes, msg + compilers = extra_attributes['compilers'] + for key in ('c', 'cxx'): + msg = '{0} compiler not found for {1}' + assert key in compilers, msg.format(key, spec) + + @property + def cc(self): + msg = "cannot retrieve C compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes['compilers'].get('c', None) + result = None + if '+clang' in self.spec: + result = os.path.join(self.spec.prefix.bin, 'clang') + return result + + @property + def cxx(self): + msg = "cannot retrieve C++ compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes['compilers'].get('cxx', None) + result = None + if '+clang' in self.spec: + result = os.path.join(self.spec.prefix.bin, 'clang++') + return result + + @property + def fc(self): + msg = "cannot retrieve Fortran compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes['compilers'].get('fc', None) + result = None + if '+flang' in self.spec: + result = os.path.join(self.spec.prefix.bin, 'flang') + return result + + @property + def f77(self): + msg = "cannot retrieve Fortran 77 compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes['compilers'].get('f77', None) + result = None + if '+flang' in self.spec: + result = os.path.join(self.spec.prefix.bin, 'flang') + return result + + @run_before('cmake') + def codesign_check(self): + if self.spec.satisfies("+code_signing"): + codesign = which('codesign') + mkdir('tmp') + llvm_check_file = join_path('tmp', 'llvm_check') + copy('/usr/bin/false', llvm_check_file) + try: + codesign('-f', '-s', 'lldb_codesign', '--dryrun', + llvm_check_file) + + except ProcessError: + # Newer LLVM versions have a simple script that sets up + # automatically when run with sudo priviliges + setup = Executable("./lldb/scripts/macos-setup-codesign.sh") + try: + setup() + except Exception: + raise RuntimeError( + 'spack was unable to either find or set up' + 'code-signing on your system. Please refer to' + 'https://lldb.llvm.org/resources/build.html#' + 'code-signing-on-macos for details on how to' + 'create this identity.' + ) + + def flag_handler(self, name, flags): + if name == 'cxxflags': + flags.append(self.compiler.cxx11_flag) + return(None, flags, None) + elif name == 'ldflags' and self.spec.satisfies('%intel'): + flags.append('-shared-intel') + return(None, flags, None) + return(flags, None, None) + + def setup_run_environment(self, env): + if "+clang" in self.spec: + env.set("CC", join_path(self.spec.prefix.bin, "clang")) + env.set("CXX", join_path(self.spec.prefix.bin, "clang++")) + if "+flang" in self.spec: + env.set("FC", join_path(self.spec.prefix.bin, "flang")) + env.set("F77", join_path(self.spec.prefix.bin, "flang")) + + root_cmakelists_dir = "llvm" + + def cmake_args(self): + spec = self.spec + python = spec['python'] + cmake_args = [ + "-DLLVM_REQUIRES_RTTI:BOOL=ON", + "-DLLVM_ENABLE_RTTI:BOOL=ON", + "-DLLVM_ENABLE_EH:BOOL=ON", + "-DCLANG_DEFAULT_OPENMP_RUNTIME:STRING=libomp", + "-DPYTHON_EXECUTABLE:PATH={0}".format(python.command.path), + "-DLIBOMP_USE_HWLOC:BOOL=ON", + "-DLIBOMP_HWLOC_INSTALL_DIR={0}".format(spec["hwloc"].prefix), + ] + + if python.version >= Version("3.0.0"): + cmake_args.append("-DPython3_EXECUTABLE={0}".format( + python.command.path)) + else: + cmake_args.append("-DPython2_EXECUTABLE={0}".format( + python.command.path)) + + projects = [] + + if "+cuda" in spec: + cmake_args.extend( + [ + "-DCUDA_TOOLKIT_ROOT_DIR:PATH=" + spec["cuda"].prefix, + "-DLIBOMPTARGET_NVPTX_COMPUTE_CAPABILITIES={0}".format( + ",".join(spec.variants["cuda_arch"].value) + ), + "-DCLANG_OPENMP_NVPTX_DEFAULT_ARCH=sm_{0}".format( + spec.variants["cuda_arch"].value[-1] + ), + ] + ) + else: + # still build libomptarget but disable cuda + cmake_args.extend( + [ + "-DCUDA_TOOLKIT_ROOT_DIR:PATH=IGNORE", + "-DCUDA_SDK_ROOT_DIR:PATH=IGNORE", + "-DCUDA_NVCC_EXECUTABLE:FILEPATH=IGNORE", + "-DLIBOMPTARGET_DEP_CUDA_DRIVER_LIBRARIES:STRING=IGNORE", + ] + ) + + if "+omp_debug" in spec: + cmake_args.append("-DLIBOMPTARGET_ENABLE_DEBUG:Bool=ON") + + if "+python" in spec and "+lldb" in spec and spec.satisfies("@5.0.0:"): + cmake_args.append("-DLLDB_USE_SYSTEM_SIX:Bool=TRUE") + + if "+lldb" in spec and spec.satisfies("@:9.9.9"): + cmake_args.append("-DLLDB_DISABLE_PYTHON:Bool={0}".format( + 'ON' if '~python' in spec else 'OFF')) + if "+lldb" in spec and spec.satisfies("@10.0.0:"): + cmake_args.append("-DLLDB_ENABLE_PYTHON:Bool={0}".format( + 'ON' if '+python' in spec else 'OFF')) + + if "+gold" in spec: + cmake_args.append( + "-DLLVM_BINUTILS_INCDIR=" + spec["binutils"].prefix.include + ) + + if "+clang" in spec: + projects.append("clang") + projects.append("clang-tools-extra") + projects.append("openmp") + if "+flang" in spec: + projects.append("flang") + if "+lldb" in spec: + projects.append("lldb") + if "+lld" in spec: + projects.append("lld") + if "+compiler-rt" in spec: + projects.append("compiler-rt") + if "+libcxx" in spec: + projects.append("libcxx") + projects.append("libcxxabi") + if "+mlir" in spec: + projects.append("mlir") + if "+internal_unwind" in spec: + projects.append("libunwind") + if "+polly" in spec: + projects.append("polly") + cmake_args.append("-DLINK_POLLY_INTO_TOOLS:Bool=ON") + + if "+shared_libs" in spec: + cmake_args.append("-DBUILD_SHARED_LIBS:Bool=ON") + if "+llvm_dylib" in spec: + cmake_args.append("-DLLVM_BUILD_LLVM_DYLIB:Bool=ON") + if "+omp_debug" in spec: + cmake_args.append("-DLIBOMPTARGET_ENABLE_DEBUG:Bool=ON") + + if "+split_dwarf" in spec: + cmake_args.append("-DLLVM_USE_SPLIT_DWARF:Bool=ON") + + if "+all_targets" not in spec: # all is default on cmake + + targets = ["NVPTX", "AMDGPU"] + if spec.version < Version("3.9.0"): + # Starting in 3.9.0 CppBackend is no longer a target (see + # LLVM_ALL_TARGETS in llvm's top-level CMakeLists.txt for + # the complete list of targets) + targets.append("CppBackend") + + if spec.target.family == "x86" or spec.target.family == "x86_64": + targets.append("X86") + elif spec.target.family == "arm": + targets.append("ARM") + elif spec.target.family == "aarch64": + targets.append("AArch64") + elif ( + spec.target.family == "sparc" + or spec.target.family == "sparc64" + ): + targets.append("Sparc") + elif ( + spec.target.family == "ppc64" + or spec.target.family == "ppc64le" + or spec.target.family == "ppc" + or spec.target.family == "ppcle" + ): + targets.append("PowerPC") + + cmake_args.append( + "-DLLVM_TARGETS_TO_BUILD:STRING=" + ";".join(targets) + ) + + if "+omp_tsan" in spec: + cmake_args.append("-DLIBOMP_TSAN_SUPPORT=ON") + + if self.compiler.name == "gcc": + compiler = Executable(self.compiler.cc) + gcc_output = compiler('-print-search-dirs', output=str, error=str) + + for line in gcc_output.splitlines(): + if line.startswith("install:"): + # Get path and strip any whitespace + # (causes oddity with ancestor) + gcc_prefix = line.split(":")[1].strip() + gcc_prefix = ancestor(gcc_prefix, 4) + break + cmake_args.append("-DGCC_INSTALL_PREFIX=" + gcc_prefix) + + if spec.satisfies("@4.0.0:"): + if spec.satisfies("platform=cray") or spec.satisfies( + "platform=linux" + ): + cmake_args.append("-DCMAKE_BUILD_WITH_INSTALL_RPATH=1") + + if self.spec.satisfies("~code_signing platform=darwin"): + cmake_args.append('-DLLDB_USE_SYSTEM_DEBUGSERVER=ON') + + # Semicolon seperated list of projects to enable + cmake_args.append( + "-DLLVM_ENABLE_PROJECTS:STRING={0}".format(";".join(projects)) + ) + + return cmake_args + + @run_before("build") + def pre_install(self): + with working_dir(self.build_directory): + # When building shared libraries these need to be installed first + make("install-LLVMTableGen") + if self.spec.version >= Version("4.0.0"): + # LLVMDemangle target was added in 4.0.0 + make("install-LLVMDemangle") + make("install-LLVMSupport") + + @run_after("install") + def post_install(self): + spec = self.spec + + # unnecessary if we get bootstrap builds in here + if "+cuda" in self.spec: + ompdir = "build-bootstrapped-omp" + # rebuild libomptarget to get bytecode runtime library files + with working_dir(ompdir, create=True): + cmake_args = [ + self.stage.source_path + "/openmp", + "-DCMAKE_C_COMPILER:PATH={0}".format( + spec.prefix.bin + "/clang" + ), + "-DCMAKE_CXX_COMPILER:PATH={0}".format( + spec.prefix.bin + "/clang++" + ), + "-DCMAKE_INSTALL_PREFIX:PATH={0}".format(spec.prefix), + ] + cmake_args.extend(self.cmake_args()) + cmake_args.append( + "-DLIBOMPTARGET_NVPTX_ENABLE_BCLIB:BOOL=TRUE" + ) + + # work around bad libelf detection in libomptarget + cmake_args.append( + "-DLIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR:String={0}".format( + spec["libelf"].prefix.include + ) + ) + + cmake(*cmake_args) + make() + make("install") + if "+python" in self.spec: + install_tree("llvm/bindings/python", site_packages_dir) + + if "+clang" in self.spec: + install_tree("clang/bindings/python", site_packages_dir) + + with working_dir(self.build_directory): + install_tree("bin", join_path(self.prefix, "libexec", "llvm")) + + def add_files_to_view(self, view, merge_map): + # we remove libgomp-related files from views as they conflict with + # gcc-ones + ignore_file_paths = [ + join_path(self.prefix, "lib", "libgomp.so"), + ] + + if self.spec.satisfies('~force_full_view'): + for path in ignore_file_paths: + if path in merge_map: + del merge_map[path] + + super(Llvm, self).add_files_to_view(view, merge_map) diff --git a/packages/llvm/thread-p9.patch b/packages/llvm/thread-p9.patch new file mode 100644 index 0000000000000000000000000000000000000000..140473a8508ada02fd50e06b18f3301bd64072d4 --- /dev/null +++ b/packages/llvm/thread-p9.patch @@ -0,0 +1,16 @@ +diff --git a/libcxx/include/thread b/libcxx/include/thread +index 02da703..d1677a1 100644 +--- a/projects/libcxx/include/thread ++++ b/projects/libcxx/include/thread +@@ -368,9 +368,9 @@ sleep_for(const chrono::duration<_Rep, _Period>& __d) + { + #if defined(_LIBCPP_COMPILER_GCC) && (__powerpc__ || __POWERPC__) + // GCC's long double const folding is incomplete for IBM128 long doubles. +- _LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max(); +-#else + _LIBCPP_CONSTEXPR duration<long double> _Max = duration<long double>(ULLONG_MAX/1000000000ULL) ; ++#else ++ _LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max(); + #endif + nanoseconds __ns; + if (__d < _Max) diff --git a/packages/visionary-dls-core/package.py b/packages/meta-brainscales/package.py similarity index 66% rename from packages/visionary-dls-core/package.py rename to packages/meta-brainscales/package.py index 6fc996810cbb1686824e25cde5f91e7a0a42fb91..4f1f7d72240c07c483cb8be6bac61f2a2fd22027 100644 --- a/packages/visionary-dls-core/package.py +++ b/packages/meta-brainscales/package.py @@ -6,7 +6,7 @@ from spack import * -class VisionaryDlsCore(Package): +class MetaBrainscales(Package): """Core package that contains dependencies of the core DLS software ONLY!""" @@ -18,27 +18,34 @@ class VisionaryDlsCore(Package): # TODO: as soon as a MetaPackage-concept has been merged, please update this package version('1.0', '372ce038842f20bf0ae02de50c26e85d', url='https://github.com/electronicvisions/spack/archive/v0.8.tar.gz') - # Depend on visionary-nux to enable joint developement of host and PPU code with one meta package - depends_on('visionary-nux ~dev') + # PPU compiler dependencies + depends_on('gettext') + depends_on('zlib') + depends_on('bison') + depends_on('flex') + depends_on('m4') + depends_on('texinfo') + depends_on('wget') + conflicts('flex', when='@2.6.3', msg='Binutils 2.25 for Nux doesn\'t build with flex 2.6.3.') - # depends_on('libusb-1.0') external dependency - depends_on('bear') + # host software dependencies depends_on('bitsery') - depends_on('boost@1.69.0: +graph+icu+mpi+python+numpy+coroutine+context+valgrind cxxstd=17') + depends_on('binutils+gold+ld+plugins') # specialize + depends_on('boost@1.69.0: +graph+icu+mpi+python+numpy+coroutine+context cxxstd=17') # specialize boost (non-clingo) depends_on('cereal') depends_on('cppcheck') depends_on('doxygen+graphviz') depends_on('genpybind@visions') depends_on('gflags') depends_on('googletest+gmock') - # depends_on('icarus') depends_on('intel-tbb') # ppu gdbserver depends_on('libelf') depends_on('liblockfile') depends_on('llvm') depends_on('log4cxx') - depends_on('munge') depends_on('pkg-config') + depends_on('python@3.7.0:') # BrainScaleS(-2) only supports Python >= 3.7 + depends_on('py-h5py') # PyNN tests need it depends_on('py-matplotlib') depends_on('py-nose') depends_on('py-numpy') @@ -48,28 +55,14 @@ class VisionaryDlsCore(Package): depends_on('py-pyelftools') depends_on('py-pylint') depends_on('py-pynn') - depends_on('py-python-usbtmc') + depends_on('py-pyyaml') depends_on('py-scipy') depends_on('py-sqlalchemy') - depends_on('util-linux') # from lib-rcf + depends_on('util-linux') depends_on('yaml-cpp+shared') - ################## - # Current fixups # - ################## - # intel-mkldnn depends on intel-mkl which also provides blas -> - # concretization error -> reinvestigate when needed - depends_on('py-torch ~mkldnn') - - # we only support Python 3.7+! - depends_on('python@3.7.0:') - - # xilinx runtime dependencies - depends_on('visionary-xilinx') + # dummy installer; it's a "meta" package def install(self, spec, prefix): mkdirp(prefix.etc) - # store a copy of this package. install(__file__, join_path(prefix.etc, spec.name + '.py')) - - # we could create some filesystem view here? diff --git a/packages/visionary-dls-core/.gitkeep b/packages/visionary-dls-core/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/packages/visionary-nux/.gitkeep b/packages/visionary-nux/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/packages/visionary-nux/package.py b/packages/visionary-nux/package.py deleted file mode 100644 index 15a6a87d369bd930dac52a839c4aae091958e3e2..0000000000000000000000000000000000000000 --- a/packages/visionary-nux/package.py +++ /dev/null @@ -1,60 +0,0 @@ -############################################################################## -# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. -# Produced at the Lawrence Livermore National Laboratory. -# -# This file is part of Spack. -# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. -# LLNL-CODE-647188 -# -# For details, see https://github.com/llnl/spack -# Please also see the LICENSE file for our notice and the LGPL. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License (as -# published by the Free Software Foundation) version 2.1, February 1999. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and -# conditions of the GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -############################################################################## -from spack import * - - -class VisionaryNux(Package): - """Visionary Meta Package""" - - homepage = '' - # some random tarball, to make `spack fetch --dependencies visionary-defaults` work - url = 'https://github.com/electronicvisions/spack/archive/v0.8.tar.gz' - - # This is only a dummy tarball (see difference between version numbers) - # TODO: as soon as a MetaPackage-concept has been merged, please update this package - version('1.0', '372ce038842f20bf0ae02de50c26e85d', url='https://github.com/electronicvisions/spack/archive/v0.8.tar.gz') - - variant('dev', default=True) - - depends_on('visionary-dev-tools', when='+dev') - - depends_on('gettext') - depends_on('zlib') - - # was bison 3.0.4 in the past - depends_on('bison') - depends_on('flex') - depends_on('m4') - depends_on('texinfo') - depends_on('wget') - - conflicts('flex', when='@2.6.3', msg='Binutils 2.25 for Nux doesn\'t build with flex 2.6.3.') - - def install(self, spec, prefix): - mkdirp(prefix.etc) - # store a copy of this package. - install(__file__, join_path(prefix.etc, 'visionary-nux.py')) - - # we could create some filesystem view here? diff --git a/spack.yaml b/spack.yaml index 6f620a1249528e3438c8965234e09208ce6e77f0..0353a1fdfd43358a24c873930927019d72b05f18 100644 --- a/spack.yaml +++ b/spack.yaml @@ -19,5 +19,5 @@ spack: - py-pynn %gcc@10.3.0 - tvb-data %gcc@10.3.0 - tvb-library ^binutils+ld+gold %gcc@10.3.0 - # BrainScaleS (plus some constraining) - #- visionary-dls-core ^py-setuptools-scm+toml ^python@3.8.0:3.8.999 ^binutils+ld ^py-astroid@2.5.6:2.6.999 ^py-scipy@:1.6.999 %gcc@10.3.0 + # BrainScaleS-2 client-side software dependencies + - meta-brainscales %gcc@10.3.0