[PATCH] D35181: Defer addition of keywords to identifier table when loading AST

2018-04-15 Thread Johann Klähn via Phabricator via cfe-commits
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 ) {
+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, , );
+
+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(), 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() {
   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 ,
- IdentifierInfoLookup* externalLookup)
-  : HashTable(8192), // Start with space for 8K identifiers.
-

[PATCH] D35181: Defer addition of keywords to identifier table when loading AST

2018-04-14 Thread Johann Klähn via Phabricator via cfe-commits
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

2018-04-04 Thread Johann Klähn via Phabricator via cfe-commits
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 ) {
+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, , );
+
+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(), 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() {
   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 ,
- IdentifierInfoLookup* externalLookup)
-  : HashTable(8192), // Start with space for 8K identifiers.
-ExternalLookup(externalLookup) {
+  

[PATCH] D35181: Defer addition of keywords to identifier table when loading AST

2017-12-20 Thread Johann Klähn via Phabricator via cfe-commits
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 ) {
+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, , );
+
+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(), 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() {
   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 ,
- IdentifierInfoLookup* externalLookup)
-  : HashTable(8192), // Start with space for 8K identifiers.
-ExternalLookup(externalLookup) {
+

[PATCH] D36952: [libclang] Add support for checking abstractness of records

2017-12-14 Thread Johann Klähn via Phabricator via cfe-commits
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] D36952: [libclang] Add support for checking abstractness of records

2017-12-12 Thread Johann Klähn via Phabricator via cfe-commits
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] D36952: [libclang] Add support for checking abstractness of records

2017-12-10 Thread Johann Klähn via Phabricator via cfe-commits
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",
+   

[PATCH] D35181: Defer addition of keywords to identifier table when loading AST

2017-12-10 Thread Johann Klähn via Phabricator via cfe-commits
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 , FileID ID,
 unsigned Column, const FormatStyle ,
 encoding::Encoding Encoding)
  : ..., IdentTable(getFormattingLangOpts(Style)),
Keywords(IdentTable), ... {

  struct AdditionalKeywords {
AdditionalKeywords(IdentifierTable ) {
  kw_final = ("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] D35181: Defer addition of keywords to identifier table when loading AST

2017-12-07 Thread Johann Klähn via Phabricator via cfe-commits
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

2017-11-19 Thread Johann Klähn via Phabricator via cfe-commits
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 ) {
+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, , );
+
+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 ,
- 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.
   AddKeywords(LangOpts);
-
-  

[PATCH] D39543: [analyzer] Document the issue hash debugging facility

2017-11-02 Thread Johann Klähn via Phabricator via cfe-commits
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] D39332: [clang-refactor] Introduce "local-qualified-rename" action.

2017-11-02 Thread Johann Klähn via Phabricator via cfe-commits
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 () {
+  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] D39217: [libclang, bindings]: add spelling location

2017-10-25 Thread Johann Klähn via Phabricator via cfe-commits
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, , , 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] D35181: Defer addition of keywords to identifier table when loading AST

2017-10-24 Thread Johann Klähn via Phabricator via cfe-commits
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] D36952: [libclang] Add support for checking abstractness of records

2017-10-24 Thread Johann Klähn via Phabricator via cfe-commits
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] D39217: [libclang, bindings]: add spelling location

2017-10-24 Thread Johann Klähn via Phabricator via cfe-commits
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] D37905: [libclang, bindings]: add spelling location

2017-10-14 Thread Johann Klähn via Phabricator via cfe-commits
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] D36955: [libclang] Visit attributes for function and class templates

2017-10-11 Thread Johann Klähn via Phabricator via cfe-commits
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] D36973: [libclang] Add support for querying cursor availability

2017-10-11 Thread Johann Klähn via Phabricator via cfe-commits
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] D36973: [libclang] Add support for querying cursor availability

2017-10-10 Thread Johann Klähn via Phabricator via cfe-commits
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] D36955: [libclang] Visit attributes for function and class templates

2017-10-10 Thread Johann Klähn via Phabricator via cfe-commits
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] D36955: [libclang] Visit attributes for function and class templates

2017-09-25 Thread Johann Klähn via Phabricator via cfe-commits
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] D36973: [libclang] Add support for querying cursor availability

2017-09-25 Thread Johann Klähn via Phabricator via cfe-commits
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] D36953: [libclang] Keep track of TranslationUnit instance when annotating tokens

2017-09-21 Thread Johann Klähn via Phabricator via cfe-commits
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] D33825: [clang-tidy] signal handler must be plain old function check

2017-09-02 Thread Johann Klähn via Phabricator via cfe-commits
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] D35271: Fix printing policy for AST context loaded from file

2017-08-25 Thread Johann Klähn via Phabricator via cfe-commits
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] D35271: Fix printing policy for AST context loaded from file

2017-08-23 Thread Johann Klähn via Phabricator via cfe-commits
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

2017-08-22 Thread Johann Klähn via Phabricator via cfe-commits
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  : TemporaryFiles)
+  llvm::sys::fs::remove(Path);
+llvm::sys::fs::remove(TestDir);
+  }
+
+  void MarkTemporaryFile(std::string ) {
+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().registerCommentOptions(

[PATCH] D36973: [libclang] Add support for querying cursor availability

2017-08-21 Thread Johann Klähn via Phabricator via cfe-commits
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] D36955: [libclang] Visit attributes for function and class templates

2017-08-21 Thread Johann Klähn via Phabricator via cfe-commits
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] D36953: [libclang] Keep track of TranslationUnit instance when annotating tokens

2017-08-21 Thread Johann Klähn via Phabricator via cfe-commits
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] D36952: [libclang] Add support for checking abstractness of records

2017-08-21 Thread Johann Klähn via Phabricator via cfe-commits
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] D35271: Fix printing policy for AST context loaded from file

2017-08-21 Thread Johann Klähn via Phabricator via cfe-commits
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] D35271: Fix printing policy for AST context loaded from file

2017-07-11 Thread Johann Klähn via Phabricator via cfe-commits
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


[PATCH] D35187: [libclang] Support for querying whether an enum is scoped

2017-07-11 Thread Johann Klähn via Phabricator via cfe-commits
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] D35187: [libclang] Support for querying whether an enum is scoped

2017-07-11 Thread Johann Klähn via Phabricator via cfe-commits
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

[PATCH] D35187: [libclang] Support for querying whether an enum is scoped

2017-07-09 Thread Johann Klähn via Phabricator via cfe-commits
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] D35181: Defer addition of keywords to identifier table when loading AST

2017-07-09 Thread Johann Klähn via Phabricator via cfe-commits
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 ) {
+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, , );
+
+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 , MemoryBufferCache ,
HeaderSearch , ModuleLoader ,
IdentifierInfoLookup *IILookup, bool OwnsHeaders,
-   TranslationUnitKind TUKind)
+   TranslationUnitKind TUKind,
+   bool DeferKeywordAddition)
 : PPOpts(std::move(PPOpts)), 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 @@
   HeaderSearch  = *AST->HeaderInfo;
   unsigned Counter;
 
+  // As