[PATCH] D36955: [libclang] Visit attributes for function and class templates
jklaehn updated this revision to Diff 118330. jklaehn added a comment. Added `c-index-test`-based test. https://reviews.llvm.org/D36955 Files: bindings/python/tests/cindex/test_cursor.py test/Index/annotate-attribute.cpp tools/libclang/CIndex.cpp Index: tools/libclang/CIndex.cpp === --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -907,16 +907,18 @@ if (VisitTemplateParameters(D->getTemplateParameters())) return true; - return VisitFunctionDecl(D->getTemplatedDecl()); + auto* FD = D->getTemplatedDecl(); + return VisitAttributes(FD) || VisitFunctionDecl(FD); } bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { // FIXME: Visit the "outer" template parameter lists on the TagDecl // before visiting these template parameters. if (VisitTemplateParameters(D->getTemplateParameters())) return true; - return VisitCXXRecordDecl(D->getTemplatedDecl()); + auto* CD = D->getTemplatedDecl(); + return VisitAttributes(CD) || VisitCXXRecordDecl(CD); } bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Index: test/Index/annotate-attribute.cpp === --- test/Index/annotate-attribute.cpp +++ test/Index/annotate-attribute.cpp @@ -16,6 +16,12 @@ void methodWithoutAttribute(); }; +template +class __attribute__((annotate("works"))) TemplateTest {}; + +template +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 @@ // 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] Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -377,6 +377,26 @@ 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 ' + (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') Index: tools/libclang/CIndex.cpp === --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -907,16 +907,18 @@ if (VisitTemplateParameters(D->getTemplateParameters())) return true; - return VisitFunctionDecl(D->getTemplatedDecl()); + auto* FD = D->getTemplatedDecl(); + return VisitAttributes(FD) || VisitFunctionDecl(FD); } bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { // FIXME: Visit the "outer" template parameter lists on the TagDecl // before visiting these template parameters. if (VisitTemplateParameters(D->getTemplateParameters())) return true; - return VisitCXXRecordDecl(D->getTemplatedDecl()); + auto* CD = D->getTemplatedDecl(); + return VisitAttributes(CD) || VisitCXXRecordDecl(CD); } bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Index: test/Index/annotate-attribute.cpp === --- test/Index/annotate-attribute.cpp +++ test/Index/annotate-attribute.cpp @@ -16,6 +16,12 @@ void methodWithoutAttribute(); }; +template +class __attribute__((annotate("works"))) TemplateTest {}; + +template +int templateFunction(T value) __attribute__((annotate("works"))); + // CHECK: ClassDecl=Test:3:7 (Definition) Extent=[3:1 - 17:2] // CHECK-NEXT: CXXAccessSpecifier=:4:1
[PATCH] D36973: [libclang] Add support for querying cursor availability
jklaehn updated this revision to Diff 118333. jklaehn added a comment. Use user-defined function for test of `AvailabilityKind.DEPRECATED`. https://reviews.llvm.org/D36973 Files: bindings/python/clang/cindex.py bindings/python/tests/cindex/test_cursor.py Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ 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 TranslationUnit @@ -385,6 +386,30 @@ 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);') Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1572,6 +1572,16 @@ 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): """ @@ -1909,6 +1919,24 @@ 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 ### @@ -3440,6 +3468,10 @@ [TranslationUnit, SourceLocation], Cursor), + ("clang_getCursorAvailability", + [Cursor], + c_int), + ("clang_getCursorDefinition", [Cursor], Cursor, @@ -4055,6 +4087,7 @@ register_enumerations() __all__ = [ +'AvailabilityKind', 'Config', 'CodeCompletionResults', 'CompilationDatabase', ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36973: [libclang] Add support for querying cursor availability
jklaehn marked an inline comment as done. jklaehn added a comment. In https://reviews.llvm.org/D36973#893851, @jbcoe wrote: > LGTM > > Would you like me to commit this for you? Yes, that would be great! https://reviews.llvm.org/D36973 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36955: [libclang] Visit attributes for function and class templates
jklaehn added a comment. In https://reviews.llvm.org/D36955#893856, @jbcoe wrote: > LGTM > > Would you like me to commit this for you? Yes, I would appreciate it. https://reviews.llvm.org/D36955 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D37905: [libclang, bindings]: add spelling location
jklaehn added inline comments. Comment at: bindings/python/clang/cindex.py:214 +class Location(object): +"""A Location is a specific kind of source location. A SourceLocation Can you also add `Location` to `__all__`? https://reviews.llvm.org/D37905 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D39217: [libclang, bindings]: add spelling location
jklaehn added inline comments. Comment at: test/Index/annotate-tokens.c:226 // CHECK-RANGE2: Punctuation: "." [55:5 - 55:6] UnexposedExpr= -// CHECK-RANGE2: Identifier: "z" [55:6 - 55:7] MemberRef=z:52:1 +// CHECK-RANGE2: Identifier: "z" [55:6 - 55:7] MemberRef=z:41:9 // CHECK-RANGE2: Punctuation: "=" [55:8 - 55:9] UnexposedExpr= Those look like an improvement to me since the `MemberRef`s of `y` and `z` no longer refer to the same line? Comment at: test/Index/c-index-getCursor-test.m:167 // CHECK: [57:1 - 57:10] FunctionDecl=f:57:6 (Definition) -// CHECK: [58:4 - 58:8] VarDecl=my_var:58:8 (Definition) +// CHECK: [58:4 - 58:8] VarDecl=my_var:2:1 (Definition) // CHECK: [58:8 - 58:15] macro expansion=CONCAT:55:9 This does not seem to refer to a valid location? (line 2 only contains a comment) https://reviews.llvm.org/D39217 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36952: [libclang] Add support for checking abstractness of records
jklaehn added a comment. ping :) https://reviews.llvm.org/D36952 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn added a comment. ping :) https://reviews.llvm.org/D35181 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D39217: [libclang, bindings]: add spelling location
jklaehn added inline comments. Comment at: test/Index/c-index-getCursor-test.m:167 // CHECK: [57:1 - 57:10] FunctionDecl=f:57:6 (Definition) -// CHECK: [58:4 - 58:8] VarDecl=my_var:58:8 (Definition) +// CHECK: [58:4 - 58:8] VarDecl=my_var:2:1 (Definition) // CHECK: [58:8 - 58:15] macro expansion=CONCAT:55:9 frutiger wrote: > jklaehn wrote: > > This does not seem to refer to a valid location? (line 2 only contains a > > comment) > I don't really understand this output. What is `-test-file-scan` supposed to > show? Given this argument `c-index-test` will use `clang_getCursor` to iterate through all cursors in the file (by calling it on each character location and checking if it is equal to the previous cursor). The numbers in brackets (e.g. `[58:4 - 58:8]`) indicate the locations for which `clang_getCursor` returned the same cursor. `VarDecl=my_var:2:1 (Definition)` is the output of `PrintCursor`. In this case `:2:1` is IIUC produced by ``` Referenced = clang_getCursorReferenced(Cursor); if (!clang_equalCursors(Referenced, clang_getNullCursor())) { if (clang_getCursorKind(Referenced) == CXCursor_OverloadedDeclRef) { // [...] } else { CXSourceLocation Loc = clang_getCursorLocation(Referenced); clang_getSpellingLocation(Loc, 0, &line, &column, 0); printf(":%d:%d", line, column); } // [...] } ``` So it is affected by the change to `clang_getSpellingLocation`. I'm not sure what the referenced cursor is in this case. Maybe it would be helpful to also print its kind. https://reviews.llvm.org/D39217 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36952: [libclang] Add support for checking abstractness of records
jklaehn added a comment. Thanks! However, compared to diff 126298 (https://reviews.llvm.org/differential/diff/126298/), there seems to be duplication in the committed change (maybe some artifacts due to rebasing/merging?). Should I submit a follow-up patch to fix this? Comment at: cfe/trunk/bindings/python/clang/cindex.py:1488 + +def is_abstract_record(self): +"""Returns True if the cursor refers to a C++ record declaration duplicate Comment at: cfe/trunk/bindings/python/clang/cindex.py:3420 + + ("clang_CXXRecord_isAbstract", + [Cursor], duplicate Comment at: cfe/trunk/bindings/python/tests/cindex/test_cursor.py:289 + +def test_is_abstract_record(self): +"""Ensure Cursor.is_abstract_record works.""" duplicate Repository: rL LLVM https://reviews.llvm.org/D36952 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn updated this revision to Diff 127685. jklaehn added a project: clang. jklaehn added a comment. ping (rebased) https://reviews.llvm.org/D35181 Files: include/clang/Basic/IdentifierTable.h lib/Basic/IdentifierTable.cpp lib/Lex/Preprocessor.cpp unittests/libclang/LibclangTest.cpp Index: unittests/libclang/LibclangTest.cpp === --- unittests/libclang/LibclangTest.cpp +++ unittests/libclang/LibclangTest.cpp @@ -572,3 +572,67 @@ 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(); +} Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -85,12 +85,14 @@ IdentifierInfoLookup *IILookup, bool OwnsHeaders, TranslationUnitKind TUKind) : PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), - FileMgr(Headers.getFileMgr()), SourceMgr(SM), - PCMCache(PCMCache), ScratchBuf(new ScratchBuffer(SourceMgr)), - HeaderInfo(Headers), TheModuleLoader(TheModuleLoader), - ExternalSource(nullptr), Identifiers(opts, IILookup), - PragmaHandlers(new PragmaNamespace(StringRef())), TUKind(TUKind), - SkipMainFilePreamble(0, true), + FileMgr(Headers.getFileMgr()), SourceMgr(SM), PCMCache(PCMCache), + ScratchBuf(new ScratchBuffer(SourceMgr)), HeaderInfo(Headers), + TheModuleLoader(TheModuleLoader), ExternalSource(nullptr), + // As the language options may have not been loaded yet (when + // deserializing an ASTUnit), adding keywords to the identifier table is + // deferred to Preprocessor::Initialize(). + Identifiers(IILookup), PragmaHandlers(new PragmaNamespace(StringRef())), + TUKind(TUKind), SkipMainFilePreamble(0, true), CurSubmoduleState(&NullSubmoduleState) { OwnsHeaderSearch = OwnsHeaders; @@ -190,6 +192,9 @@ // Initialize information about built-ins. BuiltinInfo.InitializeTarget(Target, AuxTarget); HeaderInfo.setTarget(Target); + + // Populate the identifier table with info about keywords for the current language. + Identifiers.AddKeywords(LangOpts); } void Preprocessor::InitializeForModelFile() { Index: lib/Basic/IdentifierTable.cpp === --- lib/Basic/IdentifierTable.cpp +++ lib/Basic/IdentifierTable.cpp @@ -79,16 +79,16 @@ return new EmptyLookupIterator(); } +IdentifierTable::IdentifierTable(IdentifierInfoLookup *externalLookup) +: HashTable(8192), // Start with space for 8K identifiers. + ExternalLookup(externalLookup) {} + IdentifierTable::IdentifierTable(const LangOptions &LangOpts, - IdentifierInfoLookup* externalLookup) - : HashTable(8192), // Start with space for 8K identifiers. -
[PATCH] D33825: [clang-tidy] signal handler must be plain old function check
jklaehn added inline comments. Comment at: docs/ReleaseNotes.rst:62 +<<< 2f301f50187ede4b9b8c7456ac4a67b9f7418004 - Renamed checks to use correct term "implicit conversion" instead of "implicit You missed a conflict marker here (and below in line 149). Repository: rL LLVM https://reviews.llvm.org/D33825 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36953: [libclang] Keep track of TranslationUnit instance when annotating tokens
jklaehn added a comment. In https://reviews.llvm.org/D36953#877367, @jbcoe wrote: > Do you need someone to commit this change for you? > > I'm happy to do so if you don't have commit access. Yes that would be great, thanks! https://reviews.llvm.org/D36953 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36973: [libclang] Add support for querying cursor availability
jklaehn updated this revision to Diff 116456. jklaehn marked an inline comment as done. jklaehn added a comment. Added test for `AvailabilityKind.DEPRECATED`. `NOT_ACCESSIBLE` is never returned by `clang_getCursorAvailability` but only only used in `CodeCompletionResult`. https://reviews.llvm.org/D36973 Files: bindings/python/clang/cindex.py bindings/python/tests/cindex/test_cursor.py Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ 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 TranslationUnit @@ -385,6 +386,30 @@ 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('#include \n void test(char* s) { std::gets(s); }', lang='cpp') +cursor = get_cursor(tu, 'gets') +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);') Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1572,6 +1572,16 @@ 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): """ @@ -1909,6 +1919,24 @@ 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 ### @@ -3440,6 +3468,10 @@ [TranslationUnit, SourceLocation], Cursor), + ("clang_getCursorAvailability", + [Cursor], + c_int), + ("clang_getCursorDefinition", [Cursor], Cursor, @@ -4055,6 +4087,7 @@ register_enumerations() __all__ = [ +'AvailabilityKind', 'Config', 'CodeCompletionResults', 'CompilationDatabase', ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36955: [libclang] Visit attributes for function and class templates
jklaehn added a reviewer: jbcoe. jklaehn added a comment. ping :) https://reviews.llvm.org/D36955 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn added a comment. friendly ping? :) Repository: rC Clang https://reviews.llvm.org/D35181 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn updated this revision to Diff 142579. jklaehn added a comment. Thanks for the review! As I do not have commit access, it would be great if you could commit the updated patch. https://reviews.llvm.org/D35181 Files: include/clang/Basic/IdentifierTable.h lib/Basic/IdentifierTable.cpp lib/Lex/Preprocessor.cpp unittests/libclang/LibclangTest.cpp Index: unittests/libclang/LibclangTest.cpp === --- unittests/libclang/LibclangTest.cpp +++ unittests/libclang/LibclangTest.cpp @@ -698,3 +698,67 @@ clang_disposeSourceRangeList(Ranges); } } + +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(); +} Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -85,12 +85,14 @@ IdentifierInfoLookup *IILookup, bool OwnsHeaders, TranslationUnitKind TUKind) : PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), - FileMgr(Headers.getFileMgr()), SourceMgr(SM), - PCMCache(PCMCache), ScratchBuf(new ScratchBuffer(SourceMgr)), - HeaderInfo(Headers), TheModuleLoader(TheModuleLoader), - ExternalSource(nullptr), Identifiers(opts, IILookup), - PragmaHandlers(new PragmaNamespace(StringRef())), TUKind(TUKind), - SkipMainFilePreamble(0, true), + FileMgr(Headers.getFileMgr()), SourceMgr(SM), PCMCache(PCMCache), + ScratchBuf(new ScratchBuffer(SourceMgr)), HeaderInfo(Headers), + TheModuleLoader(TheModuleLoader), ExternalSource(nullptr), + // As the language options may have not been loaded yet (when + // deserializing an ASTUnit), adding keywords to the identifier table is + // deferred to Preprocessor::Initialize(). + Identifiers(IILookup), PragmaHandlers(new PragmaNamespace(StringRef())), + TUKind(TUKind), SkipMainFilePreamble(0, true), CurSubmoduleState(&NullSubmoduleState) { OwnsHeaderSearch = OwnsHeaders; @@ -190,6 +192,9 @@ // Initialize information about built-ins. BuiltinInfo.InitializeTarget(Target, AuxTarget); HeaderInfo.setTarget(Target); + + // Populate the identifier table with info about keywords for the current language. + Identifiers.AddKeywords(LangOpts); } void Preprocessor::InitializeForModelFile() { Index: lib/Basic/IdentifierTable.cpp === --- lib/Basic/IdentifierTable.cpp +++ lib/Basic/IdentifierTable.cpp @@ -79,16 +79,16 @@ return new EmptyLookupIterator(); } +IdentifierTable::IdentifierTable(IdentifierInfoLookup *ExternalLookup) +: HashTable(8192), // Start with space for 8K identifiers. + ExternalLookup(ExternalLookup) {} + IdentifierTable::IdentifierTable(const LangOptions &LangOpts, - IdentifierInfoLookup* externalLookup) - : HashTable(8192), // St
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn added a comment. Ping, can you take another look? https://reviews.llvm.org/D35181 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn added a comment. In https://reviews.llvm.org/D35181#948925, @rsmith wrote: > LGTM, but I'd like the old `IdentifierTable` constructor to be removed if > there are no callers left. It's still being used in e.g. `FormatTokenLexer`, where the populated `IdentifierTable` is passed to the constructor of another member: FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, unsigned Column, const FormatStyle &Style, encoding::Encoding Encoding) : ..., IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), ... { struct AdditionalKeywords { AdditionalKeywords(IdentifierTable &IdentTable) { kw_final = &IdentTable.get("final"); ... Apart from this case (for which I would opt to keep the old constructor) there are three other uses which could easily be changed to the new signature. Would you prefer to land this change with the old constructor in place or should I make the required changes to remove it? https://reviews.llvm.org/D35181 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36952: [libclang] Add support for checking abstractness of records
jklaehn updated this revision to Diff 126298. jklaehn added a comment. ping (rebased) https://reviews.llvm.org/D36952 Files: bindings/python/clang/cindex.py bindings/python/tests/cindex/test_cursor.py include/clang-c/Index.h test/Index/load-classes.cpp tools/c-index-test/c-index-test.c tools/libclang/CIndex.cpp tools/libclang/libclang.exports Index: tools/libclang/libclang.exports === --- tools/libclang/libclang.exports +++ tools/libclang/libclang.exports @@ -12,6 +12,7 @@ clang_CXXMethod_isPureVirtual clang_CXXMethod_isStatic clang_CXXMethod_isVirtual +clang_CXXRecord_isAbstract clang_EnumDecl_isScoped clang_Cursor_getArgument clang_Cursor_getNumTemplateArguments Index: tools/libclang/CIndex.cpp === --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -7885,6 +7885,17 @@ 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(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; Index: tools/c-index-test/c-index-test.c === --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -804,6 +804,8 @@ 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)) Index: test/Index/load-classes.cpp === --- test/Index/load-classes.cpp +++ test/Index/load-classes.cpp @@ -29,7 +29,7 @@ } // 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] Index: include/clang-c/Index.h === --- include/clang-c/Index.h +++ 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 43 +#define CINDEX_VERSION_MINOR 44 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 1) \ @@ -4441,6 +4441,12 @@ */ 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. */ Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -275,6 +275,17 @@ self.assertTrue(foo.is_virtual_method()) self.assertFalse(bar.is_virtual_method()) +def test_is_abstract_record(self): +"""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') +self.assertTrue(cls.is_abstract_record()) + +cls = get_cursor(tu, 'Y') +self.assertFalse(cls.is_abstract_record()) + def test_is_scoped_enum(self): """Ensure Cursor.is_scoped_enum works.""" source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};' Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1479,6 +1479,12 @@ """ 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. """ @@ -3401,6 +3407,10 @@ [Cursor], bool), + ("clang_CXXRecord_isAbstract", + [Cur
[PATCH] D36952: [libclang] Add support for checking abstractness of records
jklaehn added a comment. In https://reviews.llvm.org/D36952#951616, @arphaman wrote: > LGTM Thanks! Can you submit this for me? (I do not have commit access yet.) https://reviews.llvm.org/D36952 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35271: Fix printing policy for AST context loaded from file
jklaehn added a comment. In https://reviews.llvm.org/D35271#809159, @vsk wrote: > I wonder if it's possible to do away with the calls to 'updated()'... it > seems strange that we initialize the same preprocessor repeatedly. Is there > any way to finalize an ASTInfoCollector after ReadAST happens (or > ASTReaderListeners in general)? I can look into this but would prefer to do so in a different patch, as this would require refactoring beyond this simple bug fix. Would it be okay to land this patch as-is? https://reviews.llvm.org/D35271 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36952: [libclang] Add support for checking abstractness of records
jklaehn created this revision. jklaehn added a project: clang. This patch allows checking whether a C++ record declaration is abstract through libclang and clang.cindex (Python). https://reviews.llvm.org/D36952 Files: bindings/python/clang/cindex.py bindings/python/tests/cindex/test_cursor.py include/clang-c/Index.h test/Index/load-classes.cpp tools/c-index-test/c-index-test.c tools/libclang/CIndex.cpp tools/libclang/libclang.exports Index: tools/libclang/libclang.exports === --- tools/libclang/libclang.exports +++ tools/libclang/libclang.exports @@ -12,6 +12,7 @@ clang_CXXMethod_isPureVirtual clang_CXXMethod_isStatic clang_CXXMethod_isVirtual +clang_CXXRecord_isAbstract clang_EnumDecl_isScoped clang_Cursor_getArgument clang_Cursor_getNumTemplateArguments Index: tools/libclang/CIndex.cpp === --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -7846,6 +7846,17 @@ 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(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; Index: tools/c-index-test/c-index-test.c === --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -804,6 +804,8 @@ 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)) Index: test/Index/load-classes.cpp === --- test/Index/load-classes.cpp +++ test/Index/load-classes.cpp @@ -29,7 +29,7 @@ } // 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] Index: include/clang-c/Index.h === --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -4418,6 +4418,12 @@ */ 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. */ Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -255,6 +255,17 @@ 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 {};' Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1478,6 +1478,12 @@ """ 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 @@ [Cursor], bool), + ("clang_CXXRecord_isAbstract", + [Cursor], + bool), + ("clang_EnumDecl_isScoped", [Cursor], bool), ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36953: [libclang] Keep track of TranslationUnit instance when annotating tokens
jklaehn created this revision. jklaehn added a project: clang. Previously the `_tu` was not propagated to the returned cursor, leading to errors when calling any method on that cursor (e.g. `cursor.referenced`). https://reviews.llvm.org/D36953 Files: bindings/python/clang/cindex.py bindings/python/tests/cindex/test_cursor.py Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -395,6 +395,28 @@ 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') Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -3193,6 +3193,7 @@ 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)) Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -395,6 +395,28 @@ 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') Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -3193,6 +3193,7 @@ 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)) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36955: [libclang] Visit attributes for function and class templates
jklaehn created this revision. jklaehn added a project: clang. Previously, `VisitAttributes` was not called for function and class templates and thus their attributes were not accessible using libclang. https://reviews.llvm.org/D36955 Files: bindings/python/tests/cindex/test_cursor.py tools/libclang/CIndex.cpp Index: tools/libclang/CIndex.cpp === --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -907,16 +907,18 @@ if (VisitTemplateParameters(D->getTemplateParameters())) return true; - return VisitFunctionDecl(D->getTemplatedDecl()); + auto* FD = D->getTemplatedDecl(); + return VisitAttributes(FD) || VisitFunctionDecl(FD); } bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { // FIXME: Visit the "outer" template parameter lists on the TagDecl // before visiting these template parameters. if (VisitTemplateParameters(D->getTemplateParameters())) return true; - return VisitCXXRecordDecl(D->getTemplatedDecl()); + auto* CD = D->getTemplatedDecl(); + return VisitAttributes(CD) || VisitCXXRecordDecl(CD); } bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -377,6 +377,26 @@ 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 ' + (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') Index: tools/libclang/CIndex.cpp === --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -907,16 +907,18 @@ if (VisitTemplateParameters(D->getTemplateParameters())) return true; - return VisitFunctionDecl(D->getTemplatedDecl()); + auto* FD = D->getTemplatedDecl(); + return VisitAttributes(FD) || VisitFunctionDecl(FD); } bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { // FIXME: Visit the "outer" template parameter lists on the TagDecl // before visiting these template parameters. if (VisitTemplateParameters(D->getTemplateParameters())) return true; - return VisitCXXRecordDecl(D->getTemplatedDecl()); + auto* CD = D->getTemplatedDecl(); + return VisitAttributes(CD) || VisitCXXRecordDecl(CD); } bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -377,6 +377,26 @@ 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 ' + (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') ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D36973: [libclang] Add support for querying cursor availability
jklaehn created this revision. jklaehn added a project: clang. 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. https://reviews.llvm.org/D36973 Files: bindings/python/clang/cindex.py bindings/python/tests/cindex/test_cursor.py Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ 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 TranslationUnit @@ -385,6 +386,18 @@ t = foo.result_type assert t.kind == TypeKind.INT +def test_availability(): +tu = get_tu('class A { A(A const&) = delete; };', lang='cpp') +cursors = get_cursors(tu, "A") +for c in cursors: +if c.kind == CursorKind.CLASS_DECL: +assert c.availability == AvailabilityKind.AVAILABLE +if c.kind == CursorKind.CONSTRUCTOR: +assert c.availability == AvailabilityKind.NOT_AVAILABLE +break +else: +assert False, "Could not find cursor for deleted constructor" + def test_get_tokens(): """Ensure we can map cursors back to tokens.""" tu = get_tu('int foo(int i);') Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1572,6 +1572,16 @@ 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): """ @@ -1909,6 +1919,25 @@ 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 ### @@ -3440,6 +3469,10 @@ [TranslationUnit, SourceLocation], Cursor), + ("clang_getCursorAvailability", + [Cursor], + c_int), + ("clang_getCursorDefinition", [Cursor], Cursor, Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ 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 TranslationUnit @@ -385,6 +386,18 @@ t = foo.result_type assert t.kind == TypeKind.INT +def test_availability(): +tu = get_tu('class A { A(A const&) = delete; };', lang='cpp') +cursors = get_cursors(tu, "A") +for c in cursors: +if c.kind == CursorKind.CLASS_DECL: +assert c.availability == AvailabilityKind.AVAILABLE +if c.kind == CursorKind.CONSTRUCTOR: +assert c.availability == AvailabilityKind.NOT_AVAILABLE +break +else: +assert False, "Could not find cursor for deleted constructor" + def test_get_tokens(): """Ensure we can map cursors back to tokens.""" tu = get_tu('int foo(int i);') Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1572,6 +1572,16 @@ 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): """ @@ -1909,6 +1919,25 @@ StorageClass.AUTO = StorageClass(6) StorageClass.REGISTER = StorageClass(7) +### Availability Kinds ### + +class AvailabilityKind(BaseEnumeration): +""" +Describes the availability of an entity. +"""
[PATCH] D35271: Fix printing policy for AST context loaded from file
jklaehn updated this revision to Diff 112139. jklaehn added a reviewer: akyrtzi. jklaehn added a comment. Herald added a subscriber: mgorny. Added regression test. https://reviews.llvm.org/D35271 Files: lib/Frontend/ASTUnit.cpp unittests/Frontend/ASTUnitTest.cpp unittests/Frontend/CMakeLists.txt Index: unittests/Frontend/CMakeLists.txt === --- unittests/Frontend/CMakeLists.txt +++ unittests/Frontend/CMakeLists.txt @@ -3,6 +3,7 @@ ) add_clang_unittest(FrontendTests + ASTUnitTest.cpp FrontendActionTest.cpp CodeGenActionTest.cpp ) Index: unittests/Frontend/ASTUnitTest.cpp === --- /dev/null +++ unittests/Frontend/ASTUnitTest.cpp @@ -0,0 +1,113 @@ +//===- 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 + +#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 "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +class ASTUnitTest : public ::testing::Test { + std::set TemporaryFiles; + std::string TestDir; + +public: + void SetUp() override { +llvm::SmallString<256> Dir; +ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("astunit-test", Dir)); +TestDir = Dir.str(); + } + + void TearDown() override { +for (const std::string &Path : TemporaryFiles) + llvm::sys::fs::remove(Path); +llvm::sys::fs::remove(TestDir); + } + + void MarkTemporaryFile(std::string &Filename) { +assert(!llvm::sys::path::is_absolute(Filename)); +llvm::SmallString<256> Path(TestDir); +llvm::sys::path::append(Path, Filename); +Filename = Path.str(); +TemporaryFiles.insert(Filename); +llvm::sys::fs::create_directories(llvm::sys::path::parent_path(Filename)); + } +}; + +TEST_F(ASTUnitTest, 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); + } + + std::string FileName = "empty_file.cpp"; + MarkTemporaryFile(FileName); + std::ofstream OS(FileName); + OS << ""; + ASSERT_TRUE(OS.good()); + + const char* Args[] = {"clang", "-xc++", FileName.c_str()}; + + IntrusiveRefCntPtr Diags = + CompilerInstance::createDiagnostics(new DiagnosticOptions()); + + std::shared_ptr CInvok = + createInvocationFromCommandLine(Args, Diags); + + if (!CInvok) +FAIL() << "could not create compiler invocation"; + + IntrusiveRefCntPtr VFS(new vfs::InMemoryFileSystem); + VFS->addFile(FileName, 0, llvm::MemoryBuffer::getMemBuffer("")); + FileManager *FileMgr = new FileManager(FileSystemOptions(), VFS); + auto PCHContainerOps = std::make_shared(); + + std::unique_ptr AST = ASTUnit::LoadFromCompilerInvocation( + CInvok, PCHContainerOps, Diags, FileMgr); + + if (!AST) +FAIL() << "failed to create ASTUnit"; + + EXPECT_FALSE(AST->getASTContext().getPrintingPolicy().UseVoidForZeroParams); + + std::string Path = "printing_policy.ast"; + MarkTemporaryFile(Path); + AST->Save(Path); + + EXPECT_TRUE(llvm::sys::fs::exists(Path)); + + std::unique_ptr AU = ASTUnit::LoadFromASTFile( + Path, PCHContainerOps->getRawReader(), ASTUnit::LoadEverything, Diags, + FileSystemOptions(), /*UseDebugInfo=*/false); + + if (!AU) +FAIL() << "failed to load ASTUnit"; + + EXPECT_FALSE(AU->getASTContext().getPrintingPolicy().UseVoidForZeroParams); +} + +} // anonymous namespace Index: lib/Frontend/ASTUnit.cpp === --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -542,6 +542,9 @@ // 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().registerComment
[PATCH] D35271: Fix printing policy for AST context loaded from file
jklaehn updated this revision to Diff 112334. jklaehn added a comment. Update regression test to use `createTemporaryFile()` and `tool_output_file` as suggested. https://reviews.llvm.org/D35271 Files: lib/Frontend/ASTUnit.cpp unittests/Frontend/ASTUnitTest.cpp unittests/Frontend/CMakeLists.txt Index: unittests/Frontend/CMakeLists.txt === --- unittests/Frontend/CMakeLists.txt +++ unittests/Frontend/CMakeLists.txt @@ -3,6 +3,7 @@ ) add_clang_unittest(FrontendTests + ASTUnitTest.cpp FrontendActionTest.cpp CodeGenActionTest.cpp ) Index: unittests/Frontend/ASTUnitTest.cpp === --- /dev/null +++ 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 + +#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 Diags = + CompilerInstance::createDiagnostics(new DiagnosticOptions()); + + std::shared_ptr CInvok = + createInvocationFromCommandLine(Args, Diags); + + if (!CInvok) +FAIL() << "could not create compiler invocation"; + + FileManager *FileMgr = + new FileManager(FileSystemOptions(), vfs::getRealFileSystem()); + auto PCHContainerOps = std::make_shared(); + + std::unique_ptr 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 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 Index: lib/Frontend/ASTUnit.cpp === --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -542,6 +542,9 @@ // 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( ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35271: Fix printing policy for AST context loaded from file
jklaehn marked 2 inline comments as done. jklaehn added a comment. In https://reviews.llvm.org/D35271#850472, @vsk wrote: > Thanks, LGTM! This seems like a pretty straightforward bug fix. Since it's > not my usual area maybe it'd be worth waiting a day or so for more feedback. Thanks! I do not have commit access so it would be great if you could commit it on my behalf. https://reviews.llvm.org/D35271 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn updated this revision to Diff 141033. jklaehn set the repository for this revision to rC Clang. jklaehn added a comment. ping? (rebased) Repository: rC Clang https://reviews.llvm.org/D35181 Files: include/clang/Basic/IdentifierTable.h lib/Basic/IdentifierTable.cpp lib/Lex/Preprocessor.cpp unittests/libclang/LibclangTest.cpp Index: unittests/libclang/LibclangTest.cpp === --- unittests/libclang/LibclangTest.cpp +++ unittests/libclang/LibclangTest.cpp @@ -683,3 +683,67 @@ clang_disposeSourceRangeList(Ranges); } } + +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(); +} Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -85,12 +85,14 @@ IdentifierInfoLookup *IILookup, bool OwnsHeaders, TranslationUnitKind TUKind) : PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), - FileMgr(Headers.getFileMgr()), SourceMgr(SM), - PCMCache(PCMCache), ScratchBuf(new ScratchBuffer(SourceMgr)), - HeaderInfo(Headers), TheModuleLoader(TheModuleLoader), - ExternalSource(nullptr), Identifiers(opts, IILookup), - PragmaHandlers(new PragmaNamespace(StringRef())), TUKind(TUKind), - SkipMainFilePreamble(0, true), + FileMgr(Headers.getFileMgr()), SourceMgr(SM), PCMCache(PCMCache), + ScratchBuf(new ScratchBuffer(SourceMgr)), HeaderInfo(Headers), + TheModuleLoader(TheModuleLoader), ExternalSource(nullptr), + // As the language options may have not been loaded yet (when + // deserializing an ASTUnit), adding keywords to the identifier table is + // deferred to Preprocessor::Initialize(). + Identifiers(IILookup), PragmaHandlers(new PragmaNamespace(StringRef())), + TUKind(TUKind), SkipMainFilePreamble(0, true), CurSubmoduleState(&NullSubmoduleState) { OwnsHeaderSearch = OwnsHeaders; @@ -190,6 +192,9 @@ // Initialize information about built-ins. BuiltinInfo.InitializeTarget(Target, AuxTarget); HeaderInfo.setTarget(Target); + + // Populate the identifier table with info about keywords for the current language. + Identifiers.AddKeywords(LangOpts); } void Preprocessor::InitializeForModelFile() { Index: lib/Basic/IdentifierTable.cpp === --- lib/Basic/IdentifierTable.cpp +++ lib/Basic/IdentifierTable.cpp @@ -79,16 +79,16 @@ return new EmptyLookupIterator(); } +IdentifierTable::IdentifierTable(IdentifierInfoLookup *externalLookup) +: HashTable(8192), // Start with space for 8K identifiers. + ExternalLookup(externalLookup) {} + IdentifierTable::IdentifierTable(const LangOptions &LangOpts, - IdentifierInfoLookup* externalLookup) - : HashTable(8192), // Start with space f
[PATCH] D39332: [clang-refactor] Introduce "local-qualified-rename" action.
jklaehn added a comment. I spotted two typos. :) Also, the commit message needs to be updated. Comment at: lib/Tooling/Refactoring/RefactoringActions.cpp:61 + StringRef getDescription() const override { +return "The new qualified to chagne the symbol to"; + } There is a typo here → "qualified name to change" Comment at: lib/Tooling/Refactoring/Rename/RenamingAction.cpp:105 + +const RefactoringDescriptor &QualifiedRenameRuledescribe() { + static const RefactoringDescriptor Descriptor = { missing `::`? → `::describe()` https://reviews.llvm.org/D39332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D39543: [analyzer] Document the issue hash debugging facility
jklaehn added inline comments. Comment at: docs/analyzer/DebugChecks.rst:247 + + The analyzer can generate a hash to identify repots. To debug what information + is used to calculate this hash it is possible to dump the hashed string to typo `reports`? Repository: rL LLVM https://reviews.llvm.org/D39543 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn updated this revision to Diff 123495. jklaehn added a reviewer: arphaman. jklaehn added a comment. Thanks for taking a look! I removed the constructor argument as suggested; keywords are now added in `PP.Initialize`. https://reviews.llvm.org/D35181 Files: include/clang/Basic/IdentifierTable.h lib/Basic/IdentifierTable.cpp lib/Lex/Preprocessor.cpp unittests/libclang/LibclangTest.cpp Index: unittests/libclang/LibclangTest.cpp === --- unittests/libclang/LibclangTest.cpp +++ unittests/libclang/LibclangTest.cpp @@ -572,3 +572,67 @@ 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(); +} Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -78,8 +78,11 @@ AuxTarget(nullptr), FileMgr(Headers.getFileMgr()), SourceMgr(SM), PCMCache(PCMCache), ScratchBuf(new ScratchBuffer(SourceMgr)), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader), - ExternalSource(nullptr), Identifiers(opts, IILookup), - PragmaHandlers(new PragmaNamespace(StringRef())), + ExternalSource(nullptr), + // As the language options may have not been loaded yet (when + // deserializing an ASTUnit), adding keywords to the identifier table is + // deferred to Preprocessor::Initialize(). + Identifiers(IILookup), PragmaHandlers(new PragmaNamespace(StringRef())), IncrementalProcessing(false), TUKind(TUKind), CodeComplete(nullptr), CodeCompletionFile(nullptr), CodeCompletionOffset(0), LastTokenWasAt(false), ModuleImportExpectsIdentifier(false), @@ -200,6 +203,9 @@ // Initialize information about built-ins. BuiltinInfo.InitializeTarget(Target, AuxTarget); HeaderInfo.setTarget(Target); + + // Populate the identifier table with info about keywords for the current language. + Identifiers.AddKeywords(LangOpts); } void Preprocessor::InitializeForModelFile() { Index: lib/Basic/IdentifierTable.cpp === --- lib/Basic/IdentifierTable.cpp +++ lib/Basic/IdentifierTable.cpp @@ -79,16 +79,16 @@ return new EmptyLookupIterator(); } +IdentifierTable::IdentifierTable(IdentifierInfoLookup *externalLookup) +: HashTable(8192), // Start with space for 8K identifiers. + ExternalLookup(externalLookup) {} + IdentifierTable::IdentifierTable(const LangOptions &LangOpts, - IdentifierInfoLookup* externalLookup) - : HashTable(8192), // Start with space for 8K identifiers. -ExternalLookup(externalLookup) { + IdentifierInfoLookup *externalLookup) +: IdentifierTable(externalLookup) { // Populate the identifier table with info about keywords for the current // language
[PATCH] D35181: Defer addition of keywords to identifier table when loading AST
jklaehn created this revision. 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. Prior to this change the included test would fail due to the `class` token being reported as an identifier (since the C++11 `enum class` construct is not present when using the default language options). https://reviews.llvm.org/D35181 Files: include/clang/Basic/IdentifierTable.h include/clang/Lex/Preprocessor.h lib/Basic/IdentifierTable.cpp lib/Frontend/ASTUnit.cpp lib/Lex/Preprocessor.cpp unittests/libclang/LibclangTest.cpp Index: unittests/libclang/LibclangTest.cpp === --- unittests/libclang/LibclangTest.cpp +++ unittests/libclang/LibclangTest.cpp @@ -572,3 +572,67 @@ 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(); +} Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -73,12 +73,14 @@ 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), Index: lib/Frontend/ASTUnit.cpp === --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -536,6 +536,10 @@ // 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 @@ H
[PATCH] D35187: [libclang] Support for querying whether an enum is scoped
jklaehn created this revision. This patch allows checking whether an enum declaration is scoped through libclang and clang.cindex (Python). https://reviews.llvm.org/D35187 Files: bindings/python/clang/cindex.py bindings/python/tests/cindex/test_cursor.py include/clang-c/Index.h test/Index/print-type-declaration.cpp tools/c-index-test/c-index-test.c tools/libclang/CIndex.cpp tools/libclang/libclang.exports Index: tools/libclang/libclang.exports === --- tools/libclang/libclang.exports +++ tools/libclang/libclang.exports @@ -12,6 +12,7 @@ clang_CXXMethod_isPureVirtual clang_CXXMethod_isStatic clang_CXXMethod_isVirtual +clang_EnumDecl_isScoped clang_Cursor_getArgument clang_Cursor_getNumTemplateArguments clang_Cursor_getTemplateArgumentKind Index: tools/libclang/CIndex.cpp === --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -7807,6 +7807,15 @@ return (Method && Method->isVirtual()) ? 1 : 0; } +unsigned clang_EnumDecl_isScoped(CXCursor C) { + if (!clang_isDeclaration(C.kind)) +return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const EnumDecl *Enum = D ? dyn_cast_or_null(D) : nullptr; + return (Enum && Enum->isScoped()) ? 1 : 0; +} + //===--===// // Attribute introspection. //===--===// Index: tools/c-index-test/c-index-test.c === --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -804,6 +804,8 @@ printf(" (const)"); if (clang_CXXMethod_isPureVirtual(Cursor)) printf(" (pure)"); +if (clang_EnumDecl_isScoped(Cursor)) + printf(" (scoped)"); if (clang_Cursor_isVariadic(Cursor)) printf(" (variadic)"); if (clang_Cursor_isObjCOptional(Cursor)) Index: test/Index/print-type-declaration.cpp === --- test/Index/print-type-declaration.cpp +++ test/Index/print-type-declaration.cpp @@ -7,6 +7,13 @@ auto b = a; } +enum RegularEnum {}; + +enum class ScopedEnum {}; + // RUN: c-index-test -test-print-type-declaration -std=c++11 %s | FileCheck %s // CHECK: VarDecl=a:6:8 (Definition) [typedeclaration=Test] [typekind=Record] // CHECK: VarDecl=b:7:8 (Definition) [typedeclaration=Test] [typekind=Record] +// CHECK: EnumDecl=RegularEnum:10:6 (Definition) [typedeclaration=RegularEnum] [typekind=Enum] +// CHECK: EnumDecl=ScopedEnum:12:12 (Definition) (scoped) [typedeclaration=ScopedEnum] [typekind=Enum] + Index: include/clang-c/Index.h === --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -4417,6 +4417,11 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C); /** + * \brief Determine if an enum declaration refers to a scoped enum. + */ +CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C); + +/** * \brief Determine if a C++ member function or member function template is * declared 'const'. */ Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -255,6 +255,22 @@ assert foo.is_virtual_method() assert not bar.is_virtual_method() +def test_is_scoped_enum(): +"""Ensure Cursor.is_scoped_enum works.""" +source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};' +tu = get_tu(source, lang='cpp') + +cls = get_cursor(tu, 'X') +regular_enum = get_cursor(tu, 'RegularEnum') +scoped_enum = get_cursor(tu, 'ScopedEnum') +assert cls is not None +assert regular_enum is not None +assert scoped_enum is not None + +assert not cls.is_scoped_enum() +assert not regular_enum.is_scoped_enum() +assert scoped_enum.is_scoped_enum() + def test_underlying_type(): tu = get_tu('typedef int foo;') typedef = get_cursor(tu, 'foo') Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1478,6 +1478,11 @@ """ return conf.lib.clang_CXXMethod_isVirtual(self) +def is_scoped_enum(self): +"""Returns True if the cursor refers to a scoped enum declaration. +""" +return conf.lib.clang_EnumDecl_isScoped(self) + def get_definition(self): """ If the cursor is a reference to a declaration or a declaration of @@ -3314,6 +3319,10 @@ [Cursor], bool), + ("clang_EnumDecl_isScoped", + [Cursor], + bool), + ("clang_defaultDiagnosticDisplayOptions", [], c_uint),
[PATCH] D35187: [libclang] Support for querying whether an enum is scoped
jklaehn updated this revision to Diff 106066. jklaehn added a project: clang. https://reviews.llvm.org/D35187 Files: bindings/python/clang/cindex.py bindings/python/tests/cindex/test_cursor.py include/clang-c/Index.h test/Index/print-type-declaration.cpp tools/c-index-test/c-index-test.c tools/libclang/CIndex.cpp tools/libclang/libclang.exports Index: tools/libclang/libclang.exports === --- tools/libclang/libclang.exports +++ tools/libclang/libclang.exports @@ -12,6 +12,7 @@ clang_CXXMethod_isPureVirtual clang_CXXMethod_isStatic clang_CXXMethod_isVirtual +clang_EnumDecl_isScoped clang_Cursor_getArgument clang_Cursor_getNumTemplateArguments clang_Cursor_getTemplateArgumentKind Index: tools/libclang/CIndex.cpp === --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -7807,6 +7807,15 @@ return (Method && Method->isVirtual()) ? 1 : 0; } +unsigned clang_EnumDecl_isScoped(CXCursor C) { + if (!clang_isDeclaration(C.kind)) +return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + auto *Enum = dyn_cast_or_null(D); + return (Enum && Enum->isScoped()) ? 1 : 0; +} + //===--===// // Attribute introspection. //===--===// Index: tools/c-index-test/c-index-test.c === --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -804,6 +804,8 @@ printf(" (const)"); if (clang_CXXMethod_isPureVirtual(Cursor)) printf(" (pure)"); +if (clang_EnumDecl_isScoped(Cursor)) + printf(" (scoped)"); if (clang_Cursor_isVariadic(Cursor)) printf(" (variadic)"); if (clang_Cursor_isObjCOptional(Cursor)) Index: test/Index/print-type-declaration.cpp === --- test/Index/print-type-declaration.cpp +++ test/Index/print-type-declaration.cpp @@ -7,6 +7,13 @@ auto b = a; } +enum RegularEnum {}; + +enum class ScopedEnum {}; + // RUN: c-index-test -test-print-type-declaration -std=c++11 %s | FileCheck %s // CHECK: VarDecl=a:6:8 (Definition) [typedeclaration=Test] [typekind=Record] // CHECK: VarDecl=b:7:8 (Definition) [typedeclaration=Test] [typekind=Record] +// CHECK: EnumDecl=RegularEnum:10:6 (Definition) [typedeclaration=RegularEnum] [typekind=Enum] +// CHECK: EnumDecl=ScopedEnum:12:12 (Definition) (scoped) [typedeclaration=ScopedEnum] [typekind=Enum] + Index: include/clang-c/Index.h === --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -4417,6 +4417,11 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C); /** + * \brief Determine if an enum declaration refers to a scoped enum. + */ +CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C); + +/** * \brief Determine if a C++ member function or member function template is * declared 'const'. */ Index: bindings/python/tests/cindex/test_cursor.py === --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -255,6 +255,22 @@ assert foo.is_virtual_method() assert not bar.is_virtual_method() +def test_is_scoped_enum(): +"""Ensure Cursor.is_scoped_enum works.""" +source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};' +tu = get_tu(source, lang='cpp') + +cls = get_cursor(tu, 'X') +regular_enum = get_cursor(tu, 'RegularEnum') +scoped_enum = get_cursor(tu, 'ScopedEnum') +assert cls is not None +assert regular_enum is not None +assert scoped_enum is not None + +assert not cls.is_scoped_enum() +assert not regular_enum.is_scoped_enum() +assert scoped_enum.is_scoped_enum() + def test_underlying_type(): tu = get_tu('typedef int foo;') typedef = get_cursor(tu, 'foo') Index: bindings/python/clang/cindex.py === --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1478,6 +1478,11 @@ """ return conf.lib.clang_CXXMethod_isVirtual(self) +def is_scoped_enum(self): +"""Returns True if the cursor refers to a scoped enum declaration. +""" +return conf.lib.clang_EnumDecl_isScoped(self) + def get_definition(self): """ If the cursor is a reference to a declaration or a declaration of @@ -3314,6 +3319,10 @@ [Cursor], bool), + ("clang_EnumDecl_isScoped", + [Cursor], + bool), + ("clang_defaultDiagnosticDisplayOptions", [], c_uint), ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/ma
[PATCH] D35187: [libclang] Support for querying whether an enum is scoped
jklaehn added a comment. I do not have commit access, it would be great if you could commit it. Thanks! https://reviews.llvm.org/D35187 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35271: Fix printing policy for AST context loaded from file
jklaehn created this revision. jklaehn added a project: clang. 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. https://reviews.llvm.org/D35271 Files: lib/Frontend/ASTUnit.cpp Index: lib/Frontend/ASTUnit.cpp === --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -542,6 +542,9 @@ // 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( Index: lib/Frontend/ASTUnit.cpp === --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -542,6 +542,9 @@ // 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( ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits