summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
committerdim <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
commit554bcb69c2d785a011a30e7db87a36a87fe7db10 (patch)
tree9abb1a658a297776086f4e0dfa6ca533de02104e /tools
parentbb67ca86b31f67faee50bd10c3b036d65751745a (diff)
downloadFreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.zip
FreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.tar.gz
Vendor import of clang trunk r161861:
http://llvm.org/svn/llvm-project/cfe/trunk@161861
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt9
-rw-r--r--tools/Makefile6
-rw-r--r--tools/arcmt-test/CMakeLists.txt16
-rw-r--r--tools/arcmt-test/Makefile6
-rw-r--r--tools/c-arcmt-test/CMakeLists.txt6
-rw-r--r--tools/c-arcmt-test/Makefile7
-rw-r--r--tools/c-index-test/CMakeLists.txt13
-rw-r--r--tools/c-index-test/Makefile17
-rw-r--r--tools/c-index-test/c-index-test.c606
-rw-r--r--tools/clang-check/CMakeLists.txt15
-rw-r--r--tools/clang-check/ClangCheck.cpp104
-rw-r--r--tools/clang-check/Makefile4
-rwxr-xr-xtools/diag-build/diag-build.sh115
-rw-r--r--tools/diagtool/CMakeLists.txt28
-rw-r--r--tools/diagtool/DiagnosticNames.cpp78
-rw-r--r--tools/diagtool/DiagnosticNames.h128
-rw-r--r--tools/diagtool/ListWarnings.cpp37
-rw-r--r--tools/diagtool/Makefile10
-rw-r--r--tools/diagtool/ShowEnabledWarnings.cpp148
-rw-r--r--tools/diagtool/TreeView.cpp135
-rw-r--r--tools/diagtool/diagtool_main.cpp2
-rw-r--r--tools/driver/CMakeLists.txt40
-rw-r--r--tools/driver/cc1_main.cpp4
-rw-r--r--tools/driver/cc1as_main.cpp4
-rw-r--r--tools/driver/driver.cpp16
-rw-r--r--tools/libclang/CIndex.cpp221
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp25
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp30
-rw-r--r--tools/libclang/CIndexUSRs.cpp2
-rw-r--r--tools/libclang/CMakeLists.txt76
-rw-r--r--tools/libclang/CXComment.cpp1230
-rw-r--r--tools/libclang/CXComment.h47
-rw-r--r--tools/libclang/CXCompilationDatabase.cpp129
-rw-r--r--tools/libclang/CXCursor.cpp244
-rw-r--r--tools/libclang/CXCursor.h11
-rw-r--r--tools/libclang/CXStoredDiagnostic.cpp7
-rw-r--r--tools/libclang/CXTranslationUnit.h1
-rw-r--r--tools/libclang/CXType.cpp18
-rw-r--r--tools/libclang/IndexBody.cpp16
-rw-r--r--tools/libclang/IndexDecl.cpp15
-rw-r--r--tools/libclang/IndexTypeSourceInfo.cpp4
-rw-r--r--tools/libclang/Indexing.cpp10
-rw-r--r--tools/libclang/IndexingContext.h6
-rw-r--r--tools/libclang/Makefile7
-rw-r--r--tools/libclang/RecursiveASTVisitor.h2185
-rw-r--r--tools/libclang/libclang.exports50
-rwxr-xr-xtools/scan-build/ccc-analyzer21
-rwxr-xr-xtools/scan-build/scan-build213
-rw-r--r--tools/scan-build/scan-build.1348
-rwxr-xr-xtools/scan-build/set-xcode-analyzer6
50 files changed, 6121 insertions, 355 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index ab4748d..3a6fef5 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -5,3 +5,12 @@ add_subdirectory(c-arcmt-test)
add_subdirectory(diagtool)
add_subdirectory(driver)
add_subdirectory(clang-check)
+
+# We support checking out the clang-tools-extra repository into the 'extra'
+# subdirectory. It contains tools developed as part of the Clang/LLVM project
+# on top of the Clang tooling platform. We keep them in a separate repository
+# to keep the primary Clang repository small and focused.
+if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/extra AND
+ EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/extra/CMakeLists.txt)
+ add_subdirectory(extra)
+endif()
diff --git a/tools/Makefile b/tools/Makefile
index 5059ade..e7aa2fa 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,9 +8,13 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
+
+include $(CLANG_LEVEL)/../../Makefile.config
+
DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
clang-check
-include $(CLANG_LEVEL)/../../Makefile.config
+# Recurse into the extra repository of tools if present.
+OPTIONAL_DIRS := extra
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt
index a0029b4..f36b14a 100644
--- a/tools/arcmt-test/CMakeLists.txt
+++ b/tools/arcmt-test/CMakeLists.txt
@@ -1,10 +1,6 @@
-set(LLVM_USED_LIBS
- clangARCMigrate
- clangEdit
- clangRewrite
- )
-
-set( LLVM_LINK_COMPONENTS
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
support
mc
)
@@ -12,3 +8,9 @@ set( LLVM_LINK_COMPONENTS
add_clang_executable(arcmt-test
arcmt-test.cpp
)
+
+target_link_libraries(arcmt-test
+ clangARCMigrate
+ clangEdit
+ clangRewrite
+ )
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
index 57cd574..719da75 100644
--- a/tools/arcmt-test/Makefile
+++ b/tools/arcmt-test/Makefile
@@ -16,9 +16,11 @@ TOOL_NO_EXPORTS = 1
# Don't install this. It is used for tests.
NO_INSTALL = 1
-LINK_COMPONENTS := support mc
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangARCMigrate.a clangRewrite.a \
clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
- clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a \
+ clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/c-arcmt-test/CMakeLists.txt b/tools/c-arcmt-test/CMakeLists.txt
index 351f4ad..1e72261 100644
--- a/tools/c-arcmt-test/CMakeLists.txt
+++ b/tools/c-arcmt-test/CMakeLists.txt
@@ -1,5 +1,3 @@
-set(LLVM_USED_LIBS libclang)
-
set( LLVM_LINK_COMPONENTS
support
mc
@@ -9,6 +7,10 @@ add_clang_executable(c-arcmt-test
c-arcmt-test.c
)
+target_link_libraries(c-arcmt-test
+ libclang
+ )
+
set_target_properties(c-arcmt-test
PROPERTIES
LINKER_LANGUAGE CXX)
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index 818f648..b59afda 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -16,7 +16,12 @@ TOOL_NO_EXPORTS = 1
# Don't install this. It is used for tests.
NO_INSTALL = 1
-LINK_COMPONENTS := support mc
+# Include this here so we can get the configuration of the targets that have
+# been configured for construction. We have to do this early so we can set up
+# LINK_COMPONENTS before including Makefile.rules
+include $(CLANG_LEVEL)/../../Makefile.config
+
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clang.a clangARCMigrate.a clangRewrite.a \
clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index c44b34b..6379194 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -1,5 +1,3 @@
-set(LLVM_USED_LIBS libclang)
-
set( LLVM_LINK_COMPONENTS
support
mc
@@ -9,8 +7,17 @@ add_clang_executable(c-index-test
c-index-test.c
)
+target_link_libraries(c-index-test
+ libclang
+ )
+
set_target_properties(c-index-test
PROPERTIES
LINKER_LANGUAGE CXX)
-install(TARGETS c-index-test RUNTIME DESTINATION bin)
+# If libxml2 is available, make it available for c-index-test.
+if (LIBXML2_FOUND)
+ add_definitions(${LIBXML2_DEFINITIONS} "-DCLANG_HAVE_LIBXML")
+ include_directories(${LIBXML2_INCLUDE_DIR})
+ target_link_libraries(c-index-test ${LIBXML2_LIBRARIES})
+endif()
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 03519b3..09eff0f 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -17,9 +17,22 @@ INTERNAL_TOOL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-LINK_COMPONENTS := support mc
+# Don't install this. It is used for tests.
+NO_INSTALL = 1
+
+# Include this here so we can get the configuration of the targets that have
+# been configured for construction. We have to do this early so we can set up
+# LINK_COMPONENTS before including Makefile.rules
+include $(CLANG_LEVEL)/../../Makefile.config
+
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clang.a clangFrontend.a clangDriver.a \
+ clangTooling.a \
clangSerialization.a clangParse.a clangSema.a \
- clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a
+ clangAnalysis.a clangEdit.a clangAST.a clangLex.a \
+ clangBasic.a
include $(CLANG_LEVEL)/Makefile
+
+LIBS += $(LIBXML2_LIBS)
+CPPFLAGS += $(LIBXML2_INC)
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index eb2a406..5df21ec 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1,12 +1,20 @@
/* c-index-test.c */
#include "clang-c/Index.h"
+#include "clang-c/CXCompilationDatabase.h"
+#include "llvm/Config/config.h"
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
+#ifdef CLANG_HAVE_LIBXML
+#include <libxml/parser.h>
+#include <libxml/relaxng.h>
+#include <libxml/xmlerror.h>
+#endif
+
/******************************************************************************/
/* Utility functions. */
/******************************************************************************/
@@ -25,8 +33,25 @@ char *basename(const char* path)
return((char*)path);
}
+char *dirname(char* path)
+{
+ char* base1 = (char*)strrchr(path, '/');
+ char* base2 = (char*)strrchr(path, '\\');
+ if (base1 && base2)
+ if (base1 > base2)
+ *base1 = 0;
+ else
+ *base2 = 0;
+ else if (base1)
+ *base1 = 0;
+ else if (base2)
+ *base2 = 0;
+
+ return path;
+}
#else
extern char *basename(const char *);
+extern char *dirname(char *);
#endif
/** \brief Return the default parsing options. */
@@ -41,6 +66,8 @@ static unsigned getDefaultParsingOptions() {
options &= ~CXTranslationUnit_CacheCompletionResults;
if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
options |= CXTranslationUnit_SkipFunctionBodies;
+ if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
+ options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
return options;
}
@@ -137,6 +164,7 @@ int parse_remapped_files(int argc, const char **argv, int start_arg,
(feof(to_file) ? "EOF" : "error"), semi + 1);
fclose(to_file);
free_remapped_files(*unsaved_files, i);
+ free(contents);
*unsaved_files = 0;
*num_unsaved_files = 0;
return -1;
@@ -158,10 +186,62 @@ int parse_remapped_files(int argc, const char **argv, int start_arg,
return 0;
}
+static const char *parse_comments_schema(int argc, const char **argv) {
+ const char *CommentsSchemaArg = "-comments-xml-schema=";
+ const char *CommentSchemaFile = NULL;
+
+ if (argc == 0)
+ return CommentSchemaFile;
+
+ if (!strncmp(argv[0], CommentsSchemaArg, strlen(CommentsSchemaArg)))
+ CommentSchemaFile = argv[0] + strlen(CommentsSchemaArg);
+
+ return CommentSchemaFile;
+}
+
/******************************************************************************/
/* Pretty-printing. */
/******************************************************************************/
+static const char *FileCheckPrefix = "CHECK";
+
+static void PrintCString(const char *CStr) {
+ if (CStr != NULL && CStr[0] != '\0') {
+ for ( ; *CStr; ++CStr) {
+ const char C = *CStr;
+ switch (C) {
+ case '\n': printf("\\n"); break;
+ case '\r': printf("\\r"); break;
+ case '\t': printf("\\t"); break;
+ case '\v': printf("\\v"); break;
+ case '\f': printf("\\f"); break;
+ default: putchar(C); break;
+ }
+ }
+ }
+}
+
+static void PrintCStringWithPrefix(const char *Prefix, const char *CStr) {
+ printf(" %s=[", Prefix);
+ PrintCString(CStr);
+ printf("]");
+}
+
+static void PrintCXStringAndDispose(CXString Str) {
+ PrintCString(clang_getCString(Str));
+ clang_disposeString(Str);
+}
+
+static void PrintCXStringWithPrefix(const char *Prefix, CXString Str) {
+ PrintCStringWithPrefix(Prefix, clang_getCString(Str));
+}
+
+static void PrintCXStringWithPrefixAndDispose(const char *Prefix,
+ CXString Str) {
+ PrintCStringWithPrefix(Prefix, clang_getCString(Str));
+ clang_disposeString(Str);
+}
+
static void PrintRange(CXSourceRange R, const char *str) {
CXFile begin_file, end_file;
unsigned begin_line, begin_column, end_line, end_column;
@@ -180,7 +260,302 @@ static void PrintRange(CXSourceRange R, const char *str) {
int want_display_name = 0;
-static void PrintCursor(CXCursor Cursor) {
+static void printVersion(const char *Prefix, CXVersion Version) {
+ if (Version.Major < 0)
+ return;
+ printf("%s%d", Prefix, Version.Major);
+
+ if (Version.Minor < 0)
+ return;
+ printf(".%d", Version.Minor);
+
+ if (Version.Subminor < 0)
+ return;
+ printf(".%d", Version.Subminor);
+}
+
+struct CommentASTDumpingContext {
+ int IndentLevel;
+};
+
+static void DumpCXCommentInternal(struct CommentASTDumpingContext *Ctx,
+ CXComment Comment) {
+ unsigned i;
+ unsigned e;
+ enum CXCommentKind Kind = clang_Comment_getKind(Comment);
+
+ Ctx->IndentLevel++;
+ for (i = 0, e = Ctx->IndentLevel; i != e; ++i)
+ printf(" ");
+
+ printf("(");
+ switch (Kind) {
+ case CXComment_Null:
+ printf("CXComment_Null");
+ break;
+ case CXComment_Text:
+ printf("CXComment_Text");
+ PrintCXStringWithPrefixAndDispose("Text",
+ clang_TextComment_getText(Comment));
+ if (clang_Comment_isWhitespace(Comment))
+ printf(" IsWhitespace");
+ if (clang_InlineContentComment_hasTrailingNewline(Comment))
+ printf(" HasTrailingNewline");
+ break;
+ case CXComment_InlineCommand:
+ printf("CXComment_InlineCommand");
+ PrintCXStringWithPrefixAndDispose(
+ "CommandName",
+ clang_InlineCommandComment_getCommandName(Comment));
+ switch (clang_InlineCommandComment_getRenderKind(Comment)) {
+ case CXCommentInlineCommandRenderKind_Normal:
+ printf(" RenderNormal");
+ break;
+ case CXCommentInlineCommandRenderKind_Bold:
+ printf(" RenderBold");
+ break;
+ case CXCommentInlineCommandRenderKind_Monospaced:
+ printf(" RenderMonospaced");
+ break;
+ case CXCommentInlineCommandRenderKind_Emphasized:
+ printf(" RenderEmphasized");
+ break;
+ }
+ for (i = 0, e = clang_InlineCommandComment_getNumArgs(Comment);
+ i != e; ++i) {
+ printf(" Arg[%u]=", i);
+ PrintCXStringAndDispose(
+ clang_InlineCommandComment_getArgText(Comment, i));
+ }
+ if (clang_InlineContentComment_hasTrailingNewline(Comment))
+ printf(" HasTrailingNewline");
+ break;
+ case CXComment_HTMLStartTag: {
+ unsigned NumAttrs;
+ printf("CXComment_HTMLStartTag");
+ PrintCXStringWithPrefixAndDispose(
+ "Name",
+ clang_HTMLTagComment_getTagName(Comment));
+ NumAttrs = clang_HTMLStartTag_getNumAttrs(Comment);
+ if (NumAttrs != 0) {
+ printf(" Attrs:");
+ for (i = 0; i != NumAttrs; ++i) {
+ printf(" ");
+ PrintCXStringAndDispose(clang_HTMLStartTag_getAttrName(Comment, i));
+ printf("=");
+ PrintCXStringAndDispose(clang_HTMLStartTag_getAttrValue(Comment, i));
+ }
+ }
+ if (clang_HTMLStartTagComment_isSelfClosing(Comment))
+ printf(" SelfClosing");
+ if (clang_InlineContentComment_hasTrailingNewline(Comment))
+ printf(" HasTrailingNewline");
+ break;
+ }
+ case CXComment_HTMLEndTag:
+ printf("CXComment_HTMLEndTag");
+ PrintCXStringWithPrefixAndDispose(
+ "Name",
+ clang_HTMLTagComment_getTagName(Comment));
+ if (clang_InlineContentComment_hasTrailingNewline(Comment))
+ printf(" HasTrailingNewline");
+ break;
+ case CXComment_Paragraph:
+ printf("CXComment_Paragraph");
+ if (clang_Comment_isWhitespace(Comment))
+ printf(" IsWhitespace");
+ break;
+ case CXComment_BlockCommand:
+ printf("CXComment_BlockCommand");
+ PrintCXStringWithPrefixAndDispose(
+ "CommandName",
+ clang_BlockCommandComment_getCommandName(Comment));
+ for (i = 0, e = clang_BlockCommandComment_getNumArgs(Comment);
+ i != e; ++i) {
+ printf(" Arg[%u]=", i);
+ PrintCXStringAndDispose(
+ clang_BlockCommandComment_getArgText(Comment, i));
+ }
+ break;
+ case CXComment_ParamCommand:
+ printf("CXComment_ParamCommand");
+ switch (clang_ParamCommandComment_getDirection(Comment)) {
+ case CXCommentParamPassDirection_In:
+ printf(" in");
+ break;
+ case CXCommentParamPassDirection_Out:
+ printf(" out");
+ break;
+ case CXCommentParamPassDirection_InOut:
+ printf(" in,out");
+ break;
+ }
+ if (clang_ParamCommandComment_isDirectionExplicit(Comment))
+ printf(" explicitly");
+ else
+ printf(" implicitly");
+ PrintCXStringWithPrefixAndDispose(
+ "ParamName",
+ clang_ParamCommandComment_getParamName(Comment));
+ if (clang_ParamCommandComment_isParamIndexValid(Comment))
+ printf(" ParamIndex=%u", clang_ParamCommandComment_getParamIndex(Comment));
+ else
+ printf(" ParamIndex=Invalid");
+ break;
+ case CXComment_TParamCommand:
+ printf("CXComment_TParamCommand");
+ PrintCXStringWithPrefixAndDispose(
+ "ParamName",
+ clang_TParamCommandComment_getParamName(Comment));
+ if (clang_TParamCommandComment_isParamPositionValid(Comment)) {
+ printf(" ParamPosition={");
+ for (i = 0, e = clang_TParamCommandComment_getDepth(Comment);
+ i != e; ++i) {
+ printf("%u", clang_TParamCommandComment_getIndex(Comment, i));
+ if (i != e - 1)
+ printf(", ");
+ }
+ printf("}");
+ } else
+ printf(" ParamPosition=Invalid");
+ break;
+ case CXComment_VerbatimBlockCommand:
+ printf("CXComment_VerbatimBlockCommand");
+ PrintCXStringWithPrefixAndDispose(
+ "CommandName",
+ clang_BlockCommandComment_getCommandName(Comment));
+ break;
+ case CXComment_VerbatimBlockLine:
+ printf("CXComment_VerbatimBlockLine");
+ PrintCXStringWithPrefixAndDispose(
+ "Text",
+ clang_VerbatimBlockLineComment_getText(Comment));
+ break;
+ case CXComment_VerbatimLine:
+ printf("CXComment_VerbatimLine");
+ PrintCXStringWithPrefixAndDispose(
+ "Text",
+ clang_VerbatimLineComment_getText(Comment));
+ break;
+ case CXComment_FullComment:
+ printf("CXComment_FullComment");
+ break;
+ }
+ if (Kind != CXComment_Null) {
+ const unsigned NumChildren = clang_Comment_getNumChildren(Comment);
+ unsigned i;
+ for (i = 0; i != NumChildren; ++i) {
+ printf("\n// %s: ", FileCheckPrefix);
+ DumpCXCommentInternal(Ctx, clang_Comment_getChild(Comment, i));
+ }
+ }
+ printf(")");
+ Ctx->IndentLevel--;
+}
+
+static void DumpCXComment(CXComment Comment) {
+ struct CommentASTDumpingContext Ctx;
+ Ctx.IndentLevel = 1;
+ printf("\n// %s: CommentAST=[\n// %s:", FileCheckPrefix, FileCheckPrefix);
+ DumpCXCommentInternal(&Ctx, Comment);
+ printf("]");
+}
+
+typedef struct {
+ const char *CommentSchemaFile;
+#ifdef CLANG_HAVE_LIBXML
+ xmlRelaxNGParserCtxtPtr RNGParser;
+ xmlRelaxNGPtr Schema;
+#endif
+} CommentXMLValidationData;
+
+static void ValidateCommentXML(const char *Str,
+ CommentXMLValidationData *ValidationData) {
+#ifdef CLANG_HAVE_LIBXML
+ xmlDocPtr Doc;
+ xmlRelaxNGValidCtxtPtr ValidationCtxt;
+ int status;
+
+ if (!ValidationData || !ValidationData->CommentSchemaFile)
+ return;
+
+ if (!ValidationData->RNGParser) {
+ ValidationData->RNGParser =
+ xmlRelaxNGNewParserCtxt(ValidationData->CommentSchemaFile);
+ ValidationData->Schema = xmlRelaxNGParse(ValidationData->RNGParser);
+ }
+ if (!ValidationData->RNGParser) {
+ printf(" libXMLError");
+ return;
+ }
+
+ Doc = xmlParseDoc((const xmlChar *) Str);
+
+ if (!Doc) {
+ xmlErrorPtr Error = xmlGetLastError();
+ printf(" CommentXMLInvalid [not well-formed XML: %s]", Error->message);
+ return;
+ }
+
+ ValidationCtxt = xmlRelaxNGNewValidCtxt(ValidationData->Schema);
+ status = xmlRelaxNGValidateDoc(ValidationCtxt, Doc);
+ if (!status)
+ printf(" CommentXMLValid");
+ else if (status > 0) {
+ xmlErrorPtr Error = xmlGetLastError();
+ printf(" CommentXMLInvalid [not vaild XML: %s]", Error->message);
+ } else
+ printf(" libXMLError");
+
+ xmlRelaxNGFreeValidCtxt(ValidationCtxt);
+ xmlFreeDoc(Doc);
+#endif
+}
+
+static void PrintCursorComments(CXTranslationUnit TU,
+ CXCursor Cursor,
+ CommentXMLValidationData *ValidationData) {
+ {
+ CXString RawComment;
+ const char *RawCommentCString;
+ CXString BriefComment;
+ const char *BriefCommentCString;
+
+ RawComment = clang_Cursor_getRawCommentText(Cursor);
+ RawCommentCString = clang_getCString(RawComment);
+ if (RawCommentCString != NULL && RawCommentCString[0] != '\0') {
+ PrintCStringWithPrefix("RawComment", RawCommentCString);
+ PrintRange(clang_Cursor_getCommentRange(Cursor), "RawCommentRange");
+
+ BriefComment = clang_Cursor_getBriefCommentText(Cursor);
+ BriefCommentCString = clang_getCString(BriefComment);
+ if (BriefCommentCString != NULL && BriefCommentCString[0] != '\0')
+ PrintCStringWithPrefix("BriefComment", BriefCommentCString);
+ clang_disposeString(BriefComment);
+ }
+ clang_disposeString(RawComment);
+ }
+
+ {
+ CXComment Comment = clang_Cursor_getParsedComment(Cursor);
+ if (clang_Comment_getKind(Comment) != CXComment_Null) {
+ PrintCXStringWithPrefixAndDispose("FullCommentAsHTML",
+ clang_FullComment_getAsHTML(Comment));
+ {
+ CXString XML;
+ XML = clang_FullComment_getAsXML(TU, Comment);
+ PrintCXStringWithPrefix("FullCommentAsXML", XML);
+ ValidateCommentXML(clang_getCString(XML), ValidationData);
+ clang_disposeString(XML);
+ }
+
+ DumpCXComment(Comment);
+ }
+ }
+}
+
+static void PrintCursor(CXCursor Cursor,
+ CommentXMLValidationData *ValidationData) {
CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
if (clang_isInvalid(Cursor.kind)) {
CXString ks = clang_getCursorKindSpelling(Cursor.kind);
@@ -197,6 +572,13 @@ static void PrintCursor(CXCursor Cursor) {
unsigned RefNameRangeNr;
CXSourceRange CursorExtent;
CXSourceRange RefNameRange;
+ int AlwaysUnavailable;
+ int AlwaysDeprecated;
+ CXString UnavailableMessage;
+ CXString DeprecatedMessage;
+ CXPlatformAvailability PlatformAvailability[2];
+ int NumPlatformAvailability;
+ int I;
ks = clang_getCursorKindSpelling(Cursor.kind);
string = want_display_name? clang_getCursorDisplayName(Cursor)
@@ -249,6 +631,47 @@ static void PrintCursor(CXCursor Cursor) {
break;
}
+ NumPlatformAvailability
+ = clang_getCursorPlatformAvailability(Cursor,
+ &AlwaysDeprecated,
+ &DeprecatedMessage,
+ &AlwaysUnavailable,
+ &UnavailableMessage,
+ PlatformAvailability, 2);
+ if (AlwaysUnavailable) {
+ printf(" (always unavailable: \"%s\")",
+ clang_getCString(UnavailableMessage));
+ } else if (AlwaysDeprecated) {
+ printf(" (always deprecated: \"%s\")",
+ clang_getCString(DeprecatedMessage));
+ } else {
+ for (I = 0; I != NumPlatformAvailability; ++I) {
+ if (I >= 2)
+ break;
+
+ printf(" (%s", clang_getCString(PlatformAvailability[I].Platform));
+ if (PlatformAvailability[I].Unavailable)
+ printf(", unavailable");
+ else {
+ printVersion(", introduced=", PlatformAvailability[I].Introduced);
+ printVersion(", deprecated=", PlatformAvailability[I].Deprecated);
+ printVersion(", obsoleted=", PlatformAvailability[I].Obsoleted);
+ }
+ if (clang_getCString(PlatformAvailability[I].Message)[0])
+ printf(", message=\"%s\"",
+ clang_getCString(PlatformAvailability[I].Message));
+ printf(")");
+ }
+ }
+ for (I = 0; I != NumPlatformAvailability; ++I) {
+ if (I >= 2)
+ break;
+ clang_disposeCXPlatformAvailability(PlatformAvailability + I);
+ }
+
+ clang_disposeString(DeprecatedMessage);
+ clang_disposeString(UnavailableMessage);
+
if (clang_CXXMethod_isStatic(Cursor))
printf(" (static)");
if (clang_CXXMethod_isVirtual(Cursor))
@@ -336,6 +759,8 @@ static void PrintCursor(CXCursor Cursor) {
if (!clang_equalRanges(CursorExtent, RefNameRange))
PrintRange(RefNameRange, "RefName");
}
+
+ PrintCursorComments(TU, Cursor, ValidationData);
}
}
@@ -458,17 +883,16 @@ void PrintMemoryUsage(CXTranslationUnit TU) {
/* Logic for testing traversal. */
/******************************************************************************/
-static const char *FileCheckPrefix = "CHECK";
-
static void PrintCursorExtent(CXCursor C) {
CXSourceRange extent = clang_getCursorExtent(C);
PrintRange(extent, "Extent");
}
-/* Data used by all of the visitors. */
-typedef struct {
+/* Data used by the visitors. */
+typedef struct {
CXTranslationUnit TU;
enum CXCursorKind *Filter;
+ CommentXMLValidationData ValidationData;
} VisitorData;
@@ -482,7 +906,7 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
printf("// %s: %s:%d:%d: ", FileCheckPrefix,
GetCursorSource(Cursor), line, column);
- PrintCursor(Cursor);
+ PrintCursor(Cursor, &Data->ValidationData);
PrintCursorExtent(Cursor);
printf("\n");
return CXChildVisit_Recurse;
@@ -535,7 +959,7 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
} else if (Ref.kind != CXCursor_FunctionDecl) {
printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
curLine, curColumn);
- PrintCursor(Ref);
+ PrintCursor(Ref, &Data->ValidationData);
printf("\n");
}
}
@@ -622,7 +1046,7 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
}
if (linkage) {
- PrintCursor(cursor);
+ PrintCursor(cursor, NULL);
printf("linkage=%s\n", linkage);
}
@@ -638,7 +1062,7 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
CXType T = clang_getCursorType(cursor);
CXString S = clang_getTypeKindSpelling(T.kind);
- PrintCursor(cursor);
+ PrintCursor(cursor, NULL);
printf(" typekind=%s", clang_getCString(S));
if (clang_isConstQualifiedType(T))
printf(" const");
@@ -698,7 +1122,8 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
const char *filter, const char *prefix,
CXCursorVisitor Visitor,
- PostVisitTU PV) {
+ PostVisitTU PV,
+ const char *CommentSchemaFile) {
if (prefix)
FileCheckPrefix = prefix;
@@ -729,6 +1154,11 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
Data.TU = TU;
Data.Filter = ck;
+ Data.ValidationData.CommentSchemaFile = CommentSchemaFile;
+#ifdef CLANG_HAVE_LIBXML
+ Data.ValidationData.RNGParser = NULL;
+ Data.ValidationData.Schema = NULL;
+#endif
clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
}
@@ -760,7 +1190,7 @@ int perform_test_load_tu(const char *file, const char *filter,
return 1;
}
- result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV);
+ result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL);
clang_disposeIndex(Idx);
return result;
}
@@ -770,6 +1200,7 @@ int perform_test_load_source(int argc, const char **argv,
PostVisitTU PV) {
CXIndex Idx;
CXTranslationUnit TU;
+ const char *CommentSchemaFile;
struct CXUnsavedFile *unsaved_files = 0;
int num_unsaved_files = 0;
int result;
@@ -779,6 +1210,11 @@ int perform_test_load_source(int argc, const char **argv,
!strcmp(filter, "local-display"))? 1 : 0,
/* displayDiagnosics=*/0);
+ if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
+ argc--;
+ argv++;
+ }
+
if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
clang_disposeIndex(Idx);
return -1;
@@ -796,7 +1232,8 @@ int perform_test_load_source(int argc, const char **argv,
return 1;
}
- result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
+ result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV,
+ CommentSchemaFile);
free_remapped_files(unsaved_files, num_unsaved_files);
clang_disposeIndex(Idx);
return result;
@@ -860,7 +1297,7 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
return -1;
}
- result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
+ result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL);
free_remapped_files(unsaved_files, num_unsaved_files);
clang_disposeIndex(Idx);
@@ -880,7 +1317,7 @@ static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
printf("-%s", prefix);
PrintExtent(stdout, start_line, start_col, end_line, end_col);
printf(" ");
- PrintCursor(cursor);
+ PrintCursor(cursor, NULL);
printf("\n");
}
@@ -1104,6 +1541,8 @@ void print_completion_result(CXCompletionResult *completion_result,
unsigned annotationCount;
enum CXCursorKind ParentKind;
CXString ParentName;
+ CXString BriefComment;
+ const char *BriefCommentCString;
fprintf(file, "%s:", clang_getCString(ks));
clang_disposeString(ks);
@@ -1155,6 +1594,14 @@ void print_completion_result(CXCompletionResult *completion_result,
}
clang_disposeString(ParentName);
}
+
+ BriefComment = clang_getCompletionBriefComment(
+ completion_result->CompletionString);
+ BriefCommentCString = clang_getCString(BriefComment);
+ if (BriefCommentCString && *BriefCommentCString != '\0') {
+ fprintf(file, "(brief comment: %s)", BriefCommentCString);
+ }
+ clang_disposeString(BriefComment);
fprintf(file, "\n");
}
@@ -1267,6 +1714,8 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
completionOptions |= CXCodeComplete_IncludeCodePatterns;
+ if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
+ completionOptions |= CXCodeComplete_IncludeBriefComments;
if (timing_only)
input += strlen("-code-completion-timing=");
@@ -1465,7 +1914,7 @@ static int inspect_cursor_at(int argc, const char **argv) {
unsigned line, column;
clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
printf("%d:%d ", line, column);
- PrintCursor(Cursor);
+ PrintCursor(Cursor, NULL);
PrintCursorExtent(Cursor);
Spelling = clang_getCursorSpelling(Cursor);
cspell = clang_getCString(Spelling);
@@ -1484,6 +1933,9 @@ static int inspect_cursor_at(int argc, const char **argv) {
clang_disposeString(Spelling);
if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor));
+ if (clang_Cursor_isDynamicCall(Cursor))
+ printf(" Dynamic-call");
+
if (completionString != NULL) {
printf("\nCompletion string: ");
print_completion_string(completionString, stdout);
@@ -1507,7 +1959,7 @@ static enum CXVisitorResult findFileRefsVisit(void *context,
if (clang_Range_isNull(range))
return CXVisit_Continue;
- PrintCursor(cursor);
+ PrintCursor(cursor, NULL);
PrintRange(range, "");
printf("\n");
return CXVisit_Continue;
@@ -1591,7 +2043,7 @@ static int find_file_refs_at(int argc, const char **argv) {
if (I + 1 == Repeats) {
CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
- PrintCursor(Cursor);
+ PrintCursor(Cursor, NULL);
printf("\n");
clang_findReferencesInFile(Cursor, file, visitor);
free(Locations[Loc].filename);
@@ -1789,7 +2241,7 @@ static void printEntityInfo(const char *cb,
for (i = 0; i != info->numAttributes; ++i) {
const CXIdxAttrInfo *Attr = info->attributes[i];
printf(" <attribute>: ");
- PrintCursor(Attr->cursor);
+ PrintCursor(Attr->cursor, NULL);
}
}
@@ -1797,7 +2249,7 @@ static void printBaseClassInfo(CXClientData client_data,
const CXIdxBaseClassInfo *info) {
printEntityInfo(" <base>", client_data, info->base);
printf(" | cursor: ");
- PrintCursor(info->cursor);
+ PrintCursor(info->cursor, NULL);
printf(" | loc: ");
printCXIndexLoc(info->loc, client_data);
}
@@ -1809,7 +2261,7 @@ static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
printEntityInfo(" <protocol>", client_data,
ProtoInfo->protocols[i]->protocol);
printf(" | cursor: ");
- PrintCursor(ProtoInfo->protocols[i]->cursor);
+ PrintCursor(ProtoInfo->protocols[i]->cursor, NULL);
printf(" | loc: ");
printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
printf("\n");
@@ -1899,7 +2351,7 @@ static void index_indexDeclaration(CXClientData client_data,
printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
printf(" | cursor: ");
- PrintCursor(info->cursor);
+ PrintCursor(info->cursor, NULL);
printf(" | loc: ");
printCXIndexLoc(info->loc, client_data);
printf(" | semantic-container: ");
@@ -1914,7 +2366,7 @@ static void index_indexDeclaration(CXClientData client_data,
for (i = 0; i != info->numAttributes; ++i) {
const CXIdxAttrInfo *Attr = info->attributes[i];
printf(" <attribute>: ");
- PrintCursor(Attr->cursor);
+ PrintCursor(Attr->cursor, NULL);
printf("\n");
}
@@ -1937,7 +2389,7 @@ static void index_indexDeclaration(CXClientData client_data,
printEntityInfo(" <ObjCCategoryInfo>: class", client_data,
CatInfo->objcClass);
printf(" | cursor: ");
- PrintCursor(CatInfo->classCursor);
+ PrintCursor(CatInfo->classCursor, NULL);
printf(" | loc: ");
printCXIndexLoc(CatInfo->classLoc, client_data);
printf("\n");
@@ -1981,7 +2433,7 @@ static void index_indexEntityReference(CXClientData client_data,
const CXIdxEntityRefInfo *info) {
printEntityInfo("[indexEntityReference]", client_data, info->referencedEntity);
printf(" | cursor: ");
- PrintCursor(info->cursor);
+ PrintCursor(info->cursor, NULL);
printf(" | loc: ");
printCXIndexLoc(info->loc, client_data);
printEntityInfo(" | <parent>:", client_data, info->parentEntity);
@@ -2051,7 +2503,6 @@ static int index_file(int argc, const char **argv) {
return 1;
}
idxAction = 0;
- result = 1;
index_data.check_prefix = check_prefix;
index_data.first_check_printed = 0;
@@ -2148,8 +2599,10 @@ int perform_token_annotation(int argc, const char **argv) {
&second_line, &second_column)))
return errorCode;
- if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
+ if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) {
+ free(filename);
return -1;
+ }
CIdx = clang_createIndex(0, 1);
TU = clang_parseTranslationUnit(CIdx, argv[argc - 1],
@@ -2167,8 +2620,10 @@ int perform_token_annotation(int argc, const char **argv) {
}
errorCode = 0;
- if (checkForErrors(TU) != 0)
- return -1;
+ if (checkForErrors(TU) != 0) {
+ errorCode = -1;
+ goto teardown;
+ }
if (getenv("CINDEXTEST_EDITING")) {
for (i = 0; i < 5; ++i) {
@@ -2247,7 +2702,7 @@ int perform_token_annotation(int argc, const char **argv) {
PrintExtent(stdout, start_line, start_column, end_line, end_column);
if (!clang_isInvalid(cursors[i].kind)) {
printf(" ");
- PrintCursor(cursors[i]);
+ PrintCursor(cursors[i], NULL);
}
printf("\n");
}
@@ -2263,6 +2718,89 @@ int perform_token_annotation(int argc, const char **argv) {
return errorCode;
}
+static int
+perform_test_compilation_db(const char *database, int argc, const char **argv) {
+ CXCompilationDatabase db;
+ CXCompileCommands CCmds;
+ CXCompileCommand CCmd;
+ CXCompilationDatabase_Error ec;
+ CXString wd;
+ CXString arg;
+ int errorCode = 0;
+ char *tmp;
+ unsigned len;
+ char *buildDir;
+ int i, j, a, numCmds, numArgs;
+
+ len = strlen(database);
+ tmp = (char *) malloc(len+1);
+ memcpy(tmp, database, len+1);
+ buildDir = dirname(tmp);
+
+ db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
+
+ if (db) {
+
+ if (ec!=CXCompilationDatabase_NoError) {
+ printf("unexpected error %d code while loading compilation database\n", ec);
+ errorCode = -1;
+ goto cdb_end;
+ }
+
+ for (i=0; i<argc && errorCode==0; ) {
+ if (strcmp(argv[i],"lookup")==0){
+ CCmds = clang_CompilationDatabase_getCompileCommands(db, argv[i+1]);
+
+ if (!CCmds) {
+ printf("file %s not found in compilation db\n", argv[i+1]);
+ errorCode = -1;
+ break;
+ }
+
+ numCmds = clang_CompileCommands_getSize(CCmds);
+
+ if (numCmds==0) {
+ fprintf(stderr, "should not get an empty compileCommand set for file"
+ " '%s'\n", argv[i+1]);
+ errorCode = -1;
+ break;
+ }
+
+ for (j=0; j<numCmds; ++j) {
+ CCmd = clang_CompileCommands_getCommand(CCmds, j);
+
+ wd = clang_CompileCommand_getDirectory(CCmd);
+ printf("workdir:'%s'", clang_getCString(wd));
+ clang_disposeString(wd);
+
+ printf(" cmdline:'");
+ numArgs = clang_CompileCommand_getNumArgs(CCmd);
+ for (a=0; a<numArgs; ++a) {
+ if (a) printf(" ");
+ arg = clang_CompileCommand_getArg(CCmd, a);
+ printf("%s", clang_getCString(arg));
+ clang_disposeString(arg);
+ }
+ printf("'\n");
+ }
+
+ clang_CompileCommands_dispose(CCmds);
+
+ i += 2;
+ }
+ }
+ clang_CompilationDatabase_dispose(db);
+ } else {
+ printf("database loading failed with error code %d.\n", ec);
+ errorCode = -1;
+ }
+
+cdb_end:
+ free(tmp);
+
+ return errorCode;
+}
+
/******************************************************************************/
/* USR printing. */
/******************************************************************************/
@@ -2703,6 +3241,8 @@ static void print_usage(void) {
" c-index-test -print-usr-file <file>\n"
" c-index-test -write-pch <file> <compiler arguments>\n");
fprintf(stderr,
+ " c-index-test -compilation-db [lookup <filename>] database\n");
+ fprintf(stderr,
" c-index-test -read-diagnostics <file>\n\n");
fprintf(stderr,
" <symbol filter> values:\n%s",
@@ -2788,7 +3328,9 @@ int cindextest_main(int argc, const char **argv) {
return print_usrs_file(argv[2]);
else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0)
return write_pch_file(argv[2], argc - 3, argv + 3);
-
+ else if (argc > 2 && strcmp(argv[1], "-compilation-db") == 0)
+ return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2);
+
print_usage();
return 1;
}
@@ -2815,6 +3357,10 @@ void thread_runner(void *client_data_v) {
int main(int argc, const char **argv) {
thread_info client_data;
+#ifdef CLANG_HAVE_LIBXML
+ LIBXML_TEST_VERSION
+#endif
+
if (getenv("CINDEXTEST_NOTHREADS"))
return cindextest_main(argc, argv);
diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt
index 851d6cd..85e229f 100644
--- a/tools/clang-check/CMakeLists.txt
+++ b/tools/clang-check/CMakeLists.txt
@@ -1,5 +1,18 @@
-set(LLVM_USED_LIBS clangTooling clangBasic)
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
+ support
+ mc
+ )
add_clang_executable(clang-check
ClangCheck.cpp
)
+
+target_link_libraries(clang-check
+ clangTooling
+ clangBasic
+ )
+
+install(TARGETS clang-check
+ RUNTIME DESTINATION bin)
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index d68e282..9e58077 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -1,4 +1,4 @@
-//===- examples/Tooling/ClangCheck.cpp - Clang check tool -----------------===//
+//===- tools/clang-check/ClangCheck.cpp - Clang check tool ----------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,57 +10,79 @@
// This file implements a clang-check tool that runs the
// clang::SyntaxOnlyAction over a number of translation units.
//
-// Usage:
-// clang-check <cmake-output-dir> <file1> <file2> ...
-//
-// Where <cmake-output-dir> is a CMake build directory in which a file named
-// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
-// CMake to get this output).
-//
-// <file1> ... specify the paths of files in the CMake source tree. This path
-// is looked up in the compile command database. If the path of a file is
-// absolute, it needs to point into CMake's source tree. If the path is
-// relative, the current working directory needs to be in the CMake source
-// tree and the file must be in a subdirectory of the current working
-// directory. "./" prefixes in the relative files will be automatically
-// removed, but the rest of a relative path must be a suffix of a path in
-// the compile command line database.
-//
-// For example, to use clang-check on all files in a subtree of the source
-// tree, use:
-//
-// /path/in/subtree $ find . -name '*.cpp'| xargs clang-check /path/to/source
+// This tool uses the Clang Tooling infrastructure, see
+// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+// for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/CommandLine.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/FrontendActions.h"
-#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/CommandLineClangTool.h"
#include "clang/Tooling/Tooling.h"
+using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;
-cl::opt<std::string> BuildPath(
- cl::Positional,
- cl::desc("<build-path>"));
+static const char *MoreHelpText =
+ "\tFor example, to run clang-check on all files in a subtree of the\n"
+ "\tsource tree, use:\n"
+ "\n"
+ "\t find path/in/subtree -name '*.cpp'|xargs clang-check\n"
+ "\n"
+ "\tor using a specific build path:\n"
+ "\n"
+ "\t find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
+ "\n"
+ "\tNote, that path/in/subtree and current directory should follow the\n"
+ "\trules described above.\n"
+ "\n";
-cl::list<std::string> SourcePaths(
- cl::Positional,
- cl::desc("<source0> [... <sourceN>]"),
- cl::OneOrMore);
+namespace {
+class ActionFactory {
+public:
+ ActionFactory()
+ : Options(createDriverOptTable()),
+ ASTDump(
+ "ast-dump",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_dump))),
+ ASTList(
+ "ast-list",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_list))),
+ ASTPrint(
+ "ast-print",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_print))),
+ ASTDumpFilter(
+ "ast-dump-filter",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter))) {}
-int main(int argc, const char **argv) {
- llvm::OwningPtr<CompilationDatabase> Compilations(
- FixedCompilationDatabase::loadFromCommandLine(argc, argv));
- cl::ParseCommandLineOptions(argc, argv);
- if (!Compilations) {
- std::string ErrorMessage;
- Compilations.reset(CompilationDatabase::loadFromDirectory(BuildPath,
- ErrorMessage));
- if (!Compilations)
- llvm::report_fatal_error(ErrorMessage);
+ clang::ASTConsumer *newASTConsumer() {
+ if (ASTList)
+ return clang::CreateASTDeclNodeLister();
+ if (ASTDump)
+ return clang::CreateASTDumper(ASTDumpFilter);
+ if (ASTPrint)
+ return clang::CreateASTPrinter(&llvm::outs(), ASTDumpFilter);
+ return new clang::ASTConsumer();
}
- ClangTool Tool(*Compilations, SourcePaths);
- return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
+private:
+ OwningPtr<OptTable> Options;
+ cl::opt<bool> ASTDump;
+ cl::opt<bool> ASTList;
+ cl::opt<bool> ASTPrint;
+ cl::opt<std::string> ASTDumpFilter;
+};
+}
+
+int main(int argc, const char **argv) {
+ ActionFactory Factory;
+ CommandLineClangTool Tool;
+ cl::extrahelp MoreHelp(MoreHelpText);
+ Tool.initialize(argc, argv);
+ return Tool.run(newFrontendActionFactory(&Factory));
}
diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile
index 49b1ada..6775c65 100644
--- a/tools/clang-check/Makefile
+++ b/tools/clang-check/Makefile
@@ -10,12 +10,12 @@
CLANG_LEVEL := ../..
TOOLNAME = clang-check
-NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-LINK_COMPONENTS := support mc
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
clangTooling.a clangParse.a clangSema.a clangAnalysis.a \
clangEdit.a clangAST.a clangLex.a clangBasic.a
diff --git a/tools/diag-build/diag-build.sh b/tools/diag-build/diag-build.sh
new file mode 100755
index 0000000..4fef8fb
--- /dev/null
+++ b/tools/diag-build/diag-build.sh
@@ -0,0 +1,115 @@
+#!/bin/bash
+
+print_usage () {
+ echo 'Usage: diag-build.sh [-v] xcodebuild [flags]'
+ echo ' diag-build.sh [-v] make [flags]'
+ echo ' diag-build.sh [-v] <other build command>'
+ echo
+ echo 'diagtool must be in your PATH'
+ echo 'If using an alternate build command, you must ensure that'
+ echo 'the compiler used matches the CC environment variable.'
+}
+
+# Mac OS X's BSD sed uses -E for extended regular expressions,
+# but GNU sed uses -r. Find out which one this system accepts.
+EXTENDED_SED_FLAG='-E'
+echo -n | sed $EXTENDED_SED_FLAG 's/a/b/' 2>/dev/null || EXTENDED_SED_FLAG='-r'
+
+if [[ "$1" == "-v" ]]; then
+ verbose=$1
+ shift
+fi
+
+guessing_cc=0
+
+if [[ -z "$CC" ]]; then
+ guessing_cc=1
+ if [[ -x $(dirname $0)/clang ]]; then
+ CC=$(dirname $0)/clang
+ elif [[ ! -z $(which clang) ]]; then
+ CC=$(which clang)
+ else
+ echo -n 'Error: could not find an appropriate compiler'
+ echo ' to generate build commands.' 1>&2
+ echo 'Use the CC environment variable to set one explicitly.' 1>&2
+ exit 1
+ fi
+fi
+
+if [[ -z "$CXX" ]]; then
+ if [[ -x $(dirname $0)/clang++ ]]; then
+ CXX=$(dirname $0)/clang++
+ elif [[ ! -z $(which clang++) ]]; then
+ CXX=$(which clang++)
+ else
+ CXX=$CC
+ fi
+fi
+
+diagtool=$(which diagtool)
+if [[ -z "$diagtool" ]]; then
+ if [[ -x $(dirname $0)/diagtool ]]; then
+ diagtool=$(dirname $0)/diagtool
+ else
+ echo 'Error: could not find diagtool.' 1>&2
+ exit 1
+ fi
+fi
+
+
+tool=$1
+shift
+
+if [[ -z "$tool" ]]; then
+ print_usage
+ exit 1
+elif [[ "$tool" == "xcodebuild" ]]; then
+ dry_run='-dry-run'
+ set_compiler="CC='$CC' CXX='$CXX'"
+elif [[ "$tool" == "make" ]]; then
+ dry_run='-n'
+ set_compiler="CC='$CC' CXX='$CXX'"
+else
+ echo "Warning: unknown build system '$tool'" 1>&2
+ if [[ $guessing_cc -eq 1 ]]; then
+ # FIXME: We really only need $CC /or/ $CXX
+ echo 'Error: $CC must be set for other build systems' 1>&2
+ exit 1
+ fi
+fi
+
+escape () {
+ echo $@ | sed 's:[]:\\|/.+*?^$(){}[]:\\&:g'
+}
+
+escCC=$(escape $CC)
+escCXX=$(escape $CXX)
+command=$(
+ eval $tool $dry_run $set_compiler $@ 2>/dev/null |
+ # Remove "if" early on so we can find the right command line.
+ sed $EXTENDED_SED_FLAG "s:^[[:blank:]]*if[[:blank:]]{1,}::g" |
+ # Combine lines with trailing backslashes
+ sed -e :a -e '/\\$/N; s/\\\n//; ta' |
+ grep -E "^[[:blank:]]*($escCC|$escCXX)" |
+ head -n1 |
+ sed $EXTENDED_SED_FLAG "s:($escCC|$escCXX):${diagtool//:/\\:} show-enabled:g"
+)
+
+if [[ -z "$command" ]]; then
+ echo 'Error: could not find any build commands.' 1>&2
+ if [[ "$tool" != "xcodebuild" ]]; then
+ # xcodebuild always echoes the compile commands on their own line,
+ # but other tools give no such guarantees.
+ echo -n 'This may occur if your build system embeds the call to ' 2>&1
+ echo -n 'the compiler in a larger expression. ' 2>&1
+ fi
+ exit 2
+fi
+
+# Chop off trailing '&&', '||', and ';'
+command=${command%%&&*}
+command=${command%%||*}
+command=${command%%;*}
+
+[[ -n "$verbose" ]] && echo $command
+eval $command
diff --git a/tools/diagtool/CMakeLists.txt b/tools/diagtool/CMakeLists.txt
index f1fd9de..a107cbd 100644
--- a/tools/diagtool/CMakeLists.txt
+++ b/tools/diagtool/CMakeLists.txt
@@ -1,24 +1,32 @@
-set( LLVM_LINK_COMPONENTS
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
support
- )
-
-set( LLVM_USED_LIBS
- clangBasic
- clangLex
- clangSema
+ mc
)
add_clang_executable(diagtool
diagtool_main.cpp
DiagTool.cpp
+ DiagnosticNames.cpp
ListWarnings.cpp
+ ShowEnabledWarnings.cpp
+ TreeView.cpp
)
+add_dependencies(diagtool
+ ClangDiagnosticIndexName
+ )
+
+target_link_libraries(diagtool
+ clangBasic
+ clangLex
+ clangSema
+ clangFrontend
+ )
+
if(UNIX)
set(CLANGXX_LINK_OR_COPY create_symlink)
else()
set(CLANGXX_LINK_OR_COPY copy)
endif()
-
-install(TARGETS diagtool
- RUNTIME DESTINATION bin)
diff --git a/tools/diagtool/DiagnosticNames.cpp b/tools/diagtool/DiagnosticNames.cpp
new file mode 100644
index 0000000..31f3524
--- /dev/null
+++ b/tools/diagtool/DiagnosticNames.cpp
@@ -0,0 +1,78 @@
+//===- DiagnosticNames.cpp - Defines a table of all builtin diagnostics ----==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DiagnosticNames.h"
+#include "clang/Basic/AllDiagnostics.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang;
+using namespace diagtool;
+
+static const DiagnosticRecord BuiltinDiagnosticsByName[] = {
+#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
+#include "clang/Basic/DiagnosticIndexName.inc"
+#undef DIAG_NAME_INDEX
+};
+
+llvm::ArrayRef<DiagnosticRecord> diagtool::getBuiltinDiagnosticsByName() {
+ return llvm::makeArrayRef(BuiltinDiagnosticsByName);
+}
+
+
+// FIXME: Is it worth having two tables, especially when this one can get
+// out of sync easily?
+static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
+#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER, \
+ CATEGORY) \
+ { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
+#include "clang/Basic/DiagnosticCommonKinds.inc"
+#include "clang/Basic/DiagnosticDriverKinds.inc"
+#include "clang/Basic/DiagnosticFrontendKinds.inc"
+#include "clang/Basic/DiagnosticSerializationKinds.inc"
+#include "clang/Basic/DiagnosticLexKinds.inc"
+#include "clang/Basic/DiagnosticParseKinds.inc"
+#include "clang/Basic/DiagnosticASTKinds.inc"
+#include "clang/Basic/DiagnosticCommentKinds.inc"
+#include "clang/Basic/DiagnosticSemaKinds.inc"
+#include "clang/Basic/DiagnosticAnalysisKinds.inc"
+#undef DIAG
+};
+
+static bool orderByID(const DiagnosticRecord &Left,
+ const DiagnosticRecord &Right) {
+ return Left.DiagID < Right.DiagID;
+}
+
+const DiagnosticRecord &diagtool::getDiagnosticForID(short DiagID) {
+ DiagnosticRecord Key = {0, DiagID, 0};
+
+ const DiagnosticRecord *Result =
+ std::lower_bound(BuiltinDiagnosticsByID,
+ llvm::array_endof(BuiltinDiagnosticsByID),
+ Key, orderByID);
+ assert(Result && "diagnostic not found; table may be out of date");
+ return *Result;
+}
+
+
+#define GET_DIAG_ARRAYS
+#include "clang/Basic/DiagnosticGroups.inc"
+#undef GET_DIAG_ARRAYS
+
+// Second the table of options, sorted by name for fast binary lookup.
+static const GroupRecord OptionTable[] = {
+#define GET_DIAG_TABLE
+#include "clang/Basic/DiagnosticGroups.inc"
+#undef GET_DIAG_TABLE
+};
+
+llvm::ArrayRef<GroupRecord> diagtool::getDiagnosticGroups() {
+ return llvm::makeArrayRef(OptionTable);
+}
diff --git a/tools/diagtool/DiagnosticNames.h b/tools/diagtool/DiagnosticNames.h
new file mode 100644
index 0000000..9a73158
--- /dev/null
+++ b/tools/diagtool/DiagnosticNames.h
@@ -0,0 +1,128 @@
+//===- DiagnosticNames.h - Defines a table of all builtin diagnostics ------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+
+namespace diagtool {
+
+ struct DiagnosticRecord {
+ const char *NameStr;
+ short DiagID;
+ uint8_t NameLen;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+
+ bool operator<(const DiagnosticRecord &Other) const {
+ return getName() < Other.getName();
+ }
+ };
+
+ /// \brief Get every diagnostic in the system, sorted by name.
+ llvm::ArrayRef<DiagnosticRecord> getBuiltinDiagnosticsByName();
+
+ /// \brief Get a diagnostic by its ID.
+ const DiagnosticRecord &getDiagnosticForID(short DiagID);
+
+
+ struct GroupRecord {
+ // Be safe with the size of 'NameLen' because we don't statically check if
+ // the size will fit in the field; the struct size won't decrease with a
+ // shorter type anyway.
+ size_t NameLen;
+ const char *NameStr;
+ const short *Members;
+ const short *SubGroups;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+
+ template<typename RecordType>
+ class group_iterator {
+ const short *CurrentID;
+
+ friend struct GroupRecord;
+ group_iterator(const short *Start) : CurrentID(Start) {
+ if (CurrentID && *CurrentID == -1)
+ CurrentID = 0;
+ }
+
+ public:
+ typedef RecordType value_type;
+ typedef const value_type & reference;
+ typedef const value_type * pointer;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+
+ inline reference operator*() const;
+ inline pointer operator->() const {
+ return &operator*();
+ }
+
+ inline short getID() const {
+ return *CurrentID;
+ }
+
+ group_iterator &operator++() {
+ ++CurrentID;
+ if (*CurrentID == -1)
+ CurrentID = 0;
+ return *this;
+ }
+
+ bool operator==(group_iterator &Other) const {
+ return CurrentID == Other.CurrentID;
+ }
+
+ bool operator!=(group_iterator &Other) const {
+ return CurrentID != Other.CurrentID;
+ }
+ };
+
+ typedef group_iterator<GroupRecord> subgroup_iterator;
+ subgroup_iterator subgroup_begin() const {
+ return SubGroups;
+ }
+ subgroup_iterator subgroup_end() const {
+ return 0;
+ }
+
+ typedef group_iterator<DiagnosticRecord> diagnostics_iterator;
+ diagnostics_iterator diagnostics_begin() const {
+ return Members;
+ }
+ diagnostics_iterator diagnostics_end() const {
+ return 0;
+ }
+
+ bool operator<(const GroupRecord &Other) const {
+ return getName() < Other.getName();
+ }
+ };
+
+ /// \brief Get every diagnostic group in the system, sorted by name.
+ llvm::ArrayRef<GroupRecord> getDiagnosticGroups();
+
+ template<>
+ inline GroupRecord::subgroup_iterator::reference
+ GroupRecord::subgroup_iterator::operator*() const {
+ return getDiagnosticGroups()[*CurrentID];
+ }
+
+ template<>
+ inline GroupRecord::diagnostics_iterator::reference
+ GroupRecord::diagnostics_iterator::operator*() const {
+ return getDiagnosticForID(*CurrentID);
+ }
+} // end namespace diagtool
+
diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp
index 2bbeca8..d554a2e 100644
--- a/tools/diagtool/ListWarnings.cpp
+++ b/tools/diagtool/ListWarnings.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
+#include "DiagnosticNames.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/StringMap.h"
@@ -24,28 +25,7 @@ DEF_DIAGTOOL("list-warnings",
ListWarnings)
using namespace clang;
-
-namespace {
-struct StaticDiagNameIndexRec {
- const char *NameStr;
- unsigned short DiagID;
- uint8_t NameLen;
-
- StringRef getName() const {
- return StringRef(NameStr, NameLen);
- }
-};
-}
-
-static const StaticDiagNameIndexRec StaticDiagNameIndex[] = {
-#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
-#include "clang/Basic/DiagnosticIndexName.inc"
-#undef DIAG_NAME_INDEX
- { 0, 0, 0 }
-};
-
-static const unsigned StaticDiagNameIndexSize =
- sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1;
+using namespace diagtool;
namespace {
struct Entry {
@@ -73,9 +53,11 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
std::vector<Entry> Flagged, Unflagged;
llvm::StringMap<std::vector<unsigned> > flagHistogram;
- for (const StaticDiagNameIndexRec *di = StaticDiagNameIndex, *de = StaticDiagNameIndex + StaticDiagNameIndexSize;
+ ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
+
+ for (ArrayRef<DiagnosticRecord>::iterator di = AllDiagnostics.begin(),
+ de = AllDiagnostics.end();
di != de; ++di) {
-
unsigned diagID = di->DiagID;
if (DiagnosticIDs::isBuiltinNote(diagID))
@@ -95,9 +77,6 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
}
}
- std::sort(Flagged.begin(), Flagged.end());
- std::sort(Unflagged.begin(), Unflagged.end());
-
out << "Warnings with flags (" << Flagged.size() << "):\n";
printEntries(Flagged, out);
@@ -119,6 +98,10 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
out << " Average number of diagnostics per flag: "
<< llvm::format("%.4g", avgDiagsPerFlag) << '\n';
+ out << " Number in -Wpedantic (not covered by other -W flags): "
+ << flagHistogram.GetOrCreateValue("pedantic").getValue().size()
+ << '\n';
+
out << '\n';
return 0;
diff --git a/tools/diagtool/Makefile b/tools/diagtool/Makefile
index 6e3bcfc..b629712 100644
--- a/tools/diagtool/Makefile
+++ b/tools/diagtool/Makefile
@@ -1,4 +1,4 @@
-##===- tools/driver/Makefile -------------------------------*- Makefile -*-===##
+##===- tools/diagtool/Makefile -----------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
@@ -16,9 +16,11 @@ TOOL_NO_EXPORTS := 1
# Don't install this.
NO_INSTALL = 1
-LINK_COMPONENTS := support
-
-USEDLIBS = clangBasic.a
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
+ clangSema.a clangAnalysis.a clangEdit.a clangAST.a clangLex.a \
+ clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp
new file mode 100644
index 0000000..7162451
--- /dev/null
+++ b/tools/diagtool/ShowEnabledWarnings.cpp
@@ -0,0 +1,148 @@
+//===- ShowEnabledWarnings - diagtool tool for printing enabled flags -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DiagTool.h"
+#include "DiagnosticNames.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/Support/TargetSelect.h"
+
+DEF_DIAGTOOL("show-enabled",
+ "Show which warnings are enabled for a given command line",
+ ShowEnabledWarnings)
+
+using namespace clang;
+using namespace diagtool;
+
+namespace {
+ struct PrettyDiag {
+ StringRef Name;
+ StringRef Flag;
+ DiagnosticsEngine::Level Level;
+
+ PrettyDiag(StringRef name, StringRef flag, DiagnosticsEngine::Level level)
+ : Name(name), Flag(flag), Level(level) {}
+
+ bool operator<(const PrettyDiag &x) const { return Name < x.Name; }
+ };
+}
+
+static void printUsage() {
+ llvm::errs() << "Usage: diagtool show-enabled [<flags>] <single-input.c>\n";
+}
+
+static char getCharForLevel(DiagnosticsEngine::Level Level) {
+ switch (Level) {
+ case DiagnosticsEngine::Ignored: return ' ';
+ case DiagnosticsEngine::Note: return '-';
+ case DiagnosticsEngine::Warning: return 'W';
+ case DiagnosticsEngine::Error: return 'E';
+ case DiagnosticsEngine::Fatal: return 'F';
+ }
+
+ llvm_unreachable("Unknown diagnostic level");
+}
+
+static IntrusiveRefCntPtr<DiagnosticsEngine>
+createDiagnostics(unsigned int argc, char **argv) {
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
+
+ // Buffer diagnostics from argument parsing so that we can output them using a
+ // well formed diagnostic object.
+ TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
+ IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags(
+ new DiagnosticsEngine(DiagIDs, DiagsBuffer));
+
+ // Try to build a CompilerInvocation.
+ OwningPtr<CompilerInvocation> Invocation(
+ createInvocationFromCommandLine(ArrayRef<const char *>(argv, argc),
+ InterimDiags));
+ if (!Invocation)
+ return NULL;
+
+ // Build the diagnostics parser
+ IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
+ CompilerInstance::createDiagnostics(Invocation->getDiagnosticOpts(),
+ argc, argv);
+ if (!FinalDiags)
+ return NULL;
+
+ // Flush any errors created when initializing everything. This could happen
+ // for invalid command lines, which will probably give non-sensical results.
+ DiagsBuffer->FlushDiagnostics(*FinalDiags);
+
+ return FinalDiags;
+}
+
+int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
+ // First check our one flag (--levels).
+ bool ShouldShowLevels = true;
+ if (argc > 0) {
+ StringRef FirstArg(*argv);
+ if (FirstArg.equals("--no-levels")) {
+ ShouldShowLevels = false;
+ --argc;
+ ++argv;
+ } else if (FirstArg.equals("--levels")) {
+ ShouldShowLevels = true;
+ --argc;
+ ++argv;
+ }
+ }
+
+ // Create the diagnostic engine.
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv);
+ if (!Diags) {
+ printUsage();
+ return EXIT_FAILURE;
+ }
+
+ // Now we have our diagnostics. Iterate through EVERY diagnostic and see
+ // which ones are turned on.
+ // FIXME: It would be very nice to print which flags are turning on which
+ // diagnostics, but this can be done with a diff.
+ ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
+ std::vector<PrettyDiag> Active;
+
+ for (ArrayRef<DiagnosticRecord>::iterator I = AllDiagnostics.begin(),
+ E = AllDiagnostics.end();
+ I != E; ++I) {
+ unsigned DiagID = I->DiagID;
+
+ if (DiagnosticIDs::isBuiltinNote(DiagID))
+ continue;
+
+ if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
+ continue;
+
+ DiagnosticsEngine::Level DiagLevel =
+ Diags->getDiagnosticLevel(DiagID, SourceLocation());
+ if (DiagLevel == DiagnosticsEngine::Ignored)
+ continue;
+
+ StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
+ Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel));
+ }
+
+ // Print them all out.
+ for (std::vector<PrettyDiag>::const_iterator I = Active.begin(),
+ E = Active.end(); I != E; ++I) {
+ if (ShouldShowLevels)
+ Out << getCharForLevel(I->Level) << " ";
+ Out << I->Name;
+ if (!I->Flag.empty())
+ Out << " [-W" << I->Flag << "]";
+ Out << '\n';
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp
new file mode 100644
index 0000000..9db2c26
--- /dev/null
+++ b/tools/diagtool/TreeView.cpp
@@ -0,0 +1,135 @@
+//===- TreeView.cpp - diagtool tool for printing warning flags ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This diagnostic tool
+//
+//===----------------------------------------------------------------------===//
+
+#include "DiagTool.h"
+#include "DiagnosticNames.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/Support/Format.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/AllDiagnostics.h"
+
+DEF_DIAGTOOL("tree",
+ "Show warning flags in a tree view",
+ TreeView)
+
+using namespace clang;
+using namespace diagtool;
+
+static void printUsage() {
+ llvm::errs() << "Usage: diagtool tree [--flags-only] [<diagnostic-group>]\n";
+}
+
+static void printGroup(llvm::raw_ostream &out, const GroupRecord &Group,
+ bool FlagsOnly, unsigned Indent = 0) {
+ out.indent(Indent * 2);
+ out << "-W" << Group.getName() << "\n";
+
+ ++Indent;
+ for (GroupRecord::subgroup_iterator I = Group.subgroup_begin(),
+ E = Group.subgroup_end();
+ I != E; ++I) {
+ printGroup(out, *I, FlagsOnly, Indent);
+ }
+
+ if (!FlagsOnly) {
+ for (GroupRecord::diagnostics_iterator I = Group.diagnostics_begin(),
+ E = Group.diagnostics_end();
+ I != E; ++I) {
+ out.indent(Indent * 2);
+ out << I->getName() << "\n";
+ }
+ }
+}
+
+static int showGroup(llvm::raw_ostream &out, StringRef RootGroup,
+ bool FlagsOnly) {
+ ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
+
+ GroupRecord Key = { RootGroup.size(), RootGroup.data(), 0, 0 };
+ const GroupRecord *Found =
+ std::lower_bound(AllGroups.begin(), AllGroups.end(), Key);
+
+ if (Found == AllGroups.end() || Found->getName() != RootGroup) {
+ llvm::errs() << "No such diagnostic group exists\n";
+ return 1;
+ }
+
+ printGroup(out, *Found, FlagsOnly);
+
+ return 0;
+}
+
+static int showAll(llvm::raw_ostream &out, bool FlagsOnly) {
+ ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
+ llvm::DenseSet<unsigned> NonRootGroupIDs;
+
+ for (ArrayRef<GroupRecord>::iterator I = AllGroups.begin(),
+ E = AllGroups.end();
+ I != E; ++I) {
+ for (GroupRecord::subgroup_iterator SI = I->subgroup_begin(),
+ SE = I->subgroup_end();
+ SI != SE; ++SI) {
+ NonRootGroupIDs.insert((unsigned)SI.getID());
+ }
+ }
+
+ assert(NonRootGroupIDs.size() < AllGroups.size());
+
+ for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) {
+ if (!NonRootGroupIDs.count(i))
+ printGroup(out, AllGroups[i], FlagsOnly);
+ }
+
+ return 0;
+}
+
+int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
+ // First check our one flag (--flags-only).
+ bool FlagsOnly = false;
+ if (argc > 0) {
+ StringRef FirstArg(*argv);
+ if (FirstArg.equals("--flags-only")) {
+ FlagsOnly = true;
+ --argc;
+ ++argv;
+ }
+ }
+
+ bool ShowAll = false;
+ StringRef RootGroup;
+
+ switch (argc) {
+ case 0:
+ ShowAll = true;
+ break;
+ case 1:
+ RootGroup = argv[0];
+ if (RootGroup.startswith("-W"))
+ RootGroup = RootGroup.substr(2);
+ if (RootGroup == "everything")
+ ShowAll = true;
+ // FIXME: Handle other special warning flags, like -pedantic.
+ break;
+ default:
+ printUsage();
+ return -1;
+ }
+
+ if (ShowAll)
+ return showAll(out, FlagsOnly);
+
+ return showGroup(out, RootGroup, FlagsOnly);
+}
+
diff --git a/tools/diagtool/diagtool_main.cpp b/tools/diagtool/diagtool_main.cpp
index e34f0dc..4eef54d 100644
--- a/tools/diagtool/diagtool_main.cpp
+++ b/tools/diagtool/diagtool_main.cpp
@@ -18,7 +18,7 @@ using namespace diagtool;
int main(int argc, char *argv[]) {
if (argc > 1)
if (DiagTool *tool = diagTools->getTool(argv[1]))
- return tool->run(argc - 1, &argv[2], llvm::errs());
+ return tool->run(argc - 2, &argv[2], llvm::outs());
llvm::errs() << "usage: diagtool <command> [<args>]\n\n";
diagTools->printCommands(llvm::errs());
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index ae49ac1..71d7766 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -1,4 +1,22 @@
-set( LLVM_USED_LIBS
+set( LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
+ bitreader
+ bitwriter
+ codegen
+ instrumentation
+ ipo
+ linker
+ selectiondag
+ )
+
+add_clang_executable(clang
+ driver.cpp
+ cc1_main.cpp
+ cc1as_main.cpp
+ )
+
+target_link_libraries(clang
clangFrontendTool
clangAST
clangAnalysis
@@ -19,26 +37,10 @@ set( LLVM_USED_LIBS
clangStaticAnalyzerCore
)
-set( LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
- asmparser
- bitreader
- bitwriter
- codegen
- instrumentation
- ipo
- linker
- selectiondag
- )
-
-add_clang_executable(clang
- driver.cpp
- cc1_main.cpp
- cc1as_main.cpp
- )
-
set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
+add_dependencies(clang clang-headers)
+
if(UNIX)
set(CLANGXX_LINK_OR_COPY create_symlink)
# Create a relative symlink
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index a211090..f8e8a6b 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -15,7 +15,7 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
-#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/Options.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptTable.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -58,7 +58,7 @@ static int cc1_test(DiagnosticsEngine &Diags,
llvm::errs() << "\n";
// Parse the arguments.
- OptTable *Opts = createCC1OptTable();
+ OptTable *Opts = createDriverOptTable();
unsigned MissingArgIndex, MissingArgCount;
InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd,
MissingArgIndex, MissingArgCount);
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 508d6da..7dd54bd 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -328,7 +328,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
MCCodeEmitter *CE = 0;
MCAsmBackend *MAB = 0;
if (Opts.ShowEncoding) {
- CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
+ CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
MAB = TheTarget->createMCAsmBackend(Opts.Triple);
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
@@ -342,7 +342,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
} else {
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
- MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
+ MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(Opts.Triple);
Str.reset(TheTarget->createMCObjectStreamer(Opts.Triple, Ctx, *MAB, *Out,
CE, Opts.RelaxAll,
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 8c05fff..12a9329 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/ArgList.h"
-#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/Options.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Option.h"
@@ -378,7 +378,7 @@ int main(int argc_, const char **argv_) {
DiagnosticOptions DiagOpts;
{
// Note that ParseDiagnosticArgs() uses the cc1 option table.
- OwningPtr<OptTable> CC1Opts(createCC1OptTable());
+ OwningPtr<OptTable> CC1Opts(createDriverOptTable());
unsigned MissingArgIndex, MissingArgCount;
OwningPtr<InputArgList> Args(CC1Opts->ParseArgs(argv.begin()+1, argv.end(),
MissingArgIndex, MissingArgCount));
@@ -475,6 +475,10 @@ int main(int argc_, const char **argv_) {
if (C.get())
Res = TheDriver.ExecuteCompilation(*C, FailingCommand);
+ // Force a crash to test the diagnostics.
+ if(::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
+ Res = -1;
+
// If result status is < 0, then the driver command signalled an error.
// In this case, generate additional diagnostic information if possible.
if (Res < 0)
@@ -486,5 +490,13 @@ int main(int argc_, const char **argv_) {
llvm::llvm_shutdown();
+#ifdef _WIN32
+ // Exit status should not be negative on Win32, unless abnormal termination.
+ // Once abnormal termiation was caught, negative status should not be
+ // propagated.
+ if (Res < 0)
+ Res = 1;
+#endif
+
return Res;
}
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 605cc8b..bd27b4c 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
+#include "CXComment.h"
#include "CXCursor.h"
#include "CXTranslationUnit.h"
#include "CXString.h"
@@ -61,6 +62,7 @@ CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) {
D->TUData = TU;
D->StringPool = createCXStringPool();
D->Diagnostics = 0;
+ D->OverridenCursorsPool = createOverridenCXCursorsPool();
return D;
}
@@ -1067,7 +1069,8 @@ bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
bool CursorVisitor::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD) {
if (ObjCIvarDecl *Ivar = PD->getPropertyIvarDecl())
- return Visit(MakeCursorMemberRef(Ivar, PD->getPropertyIvarDeclLoc(), TU));
+ if (PD->isIvarNameSpecified())
+ return Visit(MakeCursorMemberRef(Ivar, PD->getPropertyIvarDeclLoc(), TU));
return false;
}
@@ -2462,7 +2465,8 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
CXXIdx->getOnlyLocalDecls(),
0, 0,
/*CaptureDiagnostics=*/true,
- /*AllowPCHWithCompilerErrors=*/true);
+ /*AllowPCHWithCompilerErrors=*/true,
+ /*UserFilesAreVolatile=*/true);
return MakeCXTranslationUnit(CXXIdx, TU);
}
@@ -2521,6 +2525,8 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
= (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
bool CacheCodeCompetionResults
= options & CXTranslationUnit_CacheCompletionResults;
+ bool IncludeBriefCommentsInCodeCompletion
+ = options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
// Configure the diagnostics.
@@ -2605,8 +2611,10 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
PrecompilePreamble,
TUKind,
CacheCodeCompetionResults,
+ IncludeBriefCommentsInCodeCompletion,
/*AllowPCHWithCompilerErrors=*/true,
SkipFunctionBodies,
+ /*UserFilesAreVolatile=*/true,
&ErrUnit));
if (NumErrors != Diags->getClient()->getNumErrors()) {
@@ -2691,6 +2699,8 @@ int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+ if (!CXXUnit->hasSema())
+ return CXSaveError_InvalidTU;
SaveTranslationUnitInfo STUI = { TU, FileName, options, CXSaveError_None };
@@ -2734,6 +2744,7 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
delete static_cast<ASTUnit *>(CTUnit->TUData);
disposeCXStringPool(CTUnit->StringPool);
delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
+ disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
delete CTUnit;
}
}
@@ -2829,8 +2840,8 @@ CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
}
CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
- CXCursor Result = { CXCursor_TranslationUnit, 0, { 0, 0, TU } };
- return Result;
+ ASTUnit *CXXUnit = static_cast<ASTUnit*>(TU->TUData);
+ return MakeCXCursor(CXXUnit->getASTContext().getTranslationUnitDecl(), TU);
}
} // end: extern "C"
@@ -3501,6 +3512,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("ReturnStmt");
case CXCursor_AsmStmt:
return createCXString("AsmStmt");
+ case CXCursor_MSAsmStmt:
+ return createCXString("MSAsmStmt");
case CXCursor_ObjCAtTryStmt:
return createCXString("ObjCAtTryStmt");
case CXCursor_ObjCAtCatchStmt:
@@ -3609,12 +3622,15 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
struct GetCursorData {
SourceLocation TokenBeginLoc;
bool PointsAtMacroArgExpansion;
+ bool VisitedObjCPropertyImplDecl;
+ SourceLocation VisitedDeclaratorDeclStartLoc;
CXCursor &BestCursor;
GetCursorData(SourceManager &SM,
SourceLocation tokenBegin, CXCursor &outputCursor)
: TokenBeginLoc(tokenBegin), BestCursor(outputCursor) {
PointsAtMacroArgExpansion = SM.isMacroArgExpansion(tokenBegin);
+ VisitedObjCPropertyImplDecl = false;
}
};
@@ -3654,6 +3670,32 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
!ID->isThisDeclarationADefinition())
return CXChildVisit_Break;
}
+
+ } else if (DeclaratorDecl *DD
+ = dyn_cast_or_null<DeclaratorDecl>(getCursorDecl(cursor))) {
+ SourceLocation StartLoc = DD->getSourceRange().getBegin();
+ // Check that when we have multiple declarators in the same line,
+ // that later ones do not override the previous ones.
+ // If we have:
+ // int Foo, Bar;
+ // source ranges for both start at 'int', so 'Bar' will end up overriding
+ // 'Foo' even though the cursor location was at 'Foo'.
+ if (Data->VisitedDeclaratorDeclStartLoc == StartLoc)
+ return CXChildVisit_Break;
+ Data->VisitedDeclaratorDeclStartLoc = StartLoc;
+
+ } else if (ObjCPropertyImplDecl *PropImp
+ = dyn_cast_or_null<ObjCPropertyImplDecl>(getCursorDecl(cursor))) {
+ (void)PropImp;
+ // Check that when we have multiple @synthesize in the same line,
+ // that later ones do not override the previous ones.
+ // If we have:
+ // @synthesize Foo, Bar;
+ // source ranges for both start at '@', so 'Bar' will end up overriding
+ // 'Foo' even though the cursor location was at 'Foo'.
+ if (Data->VisitedObjCPropertyImplDecl)
+ return CXChildVisit_Break;
+ Data->VisitedObjCPropertyImplDecl = true;
}
}
@@ -5487,6 +5529,90 @@ enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
return CXAvailability_Available;
}
+static CXVersion convertVersion(VersionTuple In) {
+ CXVersion Out = { -1, -1, -1 };
+ if (In.empty())
+ return Out;
+
+ Out.Major = In.getMajor();
+
+ if (llvm::Optional<unsigned> Minor = In.getMinor())
+ Out.Minor = *Minor;
+ else
+ return Out;
+
+ if (llvm::Optional<unsigned> Subminor = In.getSubminor())
+ Out.Subminor = *Subminor;
+
+ return Out;
+}
+
+int clang_getCursorPlatformAvailability(CXCursor cursor,
+ int *always_deprecated,
+ CXString *deprecated_message,
+ int *always_unavailable,
+ CXString *unavailable_message,
+ CXPlatformAvailability *availability,
+ int availability_size) {
+ if (always_deprecated)
+ *always_deprecated = 0;
+ if (deprecated_message)
+ *deprecated_message = cxstring::createCXString("", /*DupString=*/false);
+ if (always_unavailable)
+ *always_unavailable = 0;
+ if (unavailable_message)
+ *unavailable_message = cxstring::createCXString("", /*DupString=*/false);
+
+ if (!clang_isDeclaration(cursor.kind))
+ return 0;
+
+ Decl *D = cxcursor::getCursorDecl(cursor);
+ if (!D)
+ return 0;
+
+ int N = 0;
+ for (Decl::attr_iterator A = D->attr_begin(), AEnd = D->attr_end(); A != AEnd;
+ ++A) {
+ if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) {
+ if (always_deprecated)
+ *always_deprecated = 1;
+ if (deprecated_message)
+ *deprecated_message = cxstring::createCXString(Deprecated->getMessage());
+ continue;
+ }
+
+ if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) {
+ if (always_unavailable)
+ *always_unavailable = 1;
+ if (unavailable_message) {
+ *unavailable_message
+ = cxstring::createCXString(Unavailable->getMessage());
+ }
+ continue;
+ }
+
+ if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(*A)) {
+ if (N < availability_size) {
+ availability[N].Platform
+ = cxstring::createCXString(Avail->getPlatform()->getName());
+ availability[N].Introduced = convertVersion(Avail->getIntroduced());
+ availability[N].Deprecated = convertVersion(Avail->getDeprecated());
+ availability[N].Obsoleted = convertVersion(Avail->getObsoleted());
+ availability[N].Unavailable = Avail->getUnavailable();
+ availability[N].Message = cxstring::createCXString(Avail->getMessage());
+ }
+ ++N;
+ }
+ }
+
+ return N;
+}
+
+void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
+ clang_disposeString(availability->Platform);
+ clang_disposeString(availability->Message);
+}
+
CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
if (clang_isDeclaration(cursor.kind))
return getDeclLanguage(cxcursor::getCursorDecl(cursor));
@@ -5549,44 +5675,73 @@ CXCursor clang_getCursorLexicalParent(CXCursor cursor) {
return clang_getNullCursor();
}
-void clang_getOverriddenCursors(CXCursor cursor,
- CXCursor **overridden,
- unsigned *num_overridden) {
- if (overridden)
- *overridden = 0;
- if (num_overridden)
- *num_overridden = 0;
- if (!overridden || !num_overridden)
- return;
- if (!clang_isDeclaration(cursor.kind))
- return;
+CXFile clang_getIncludedFile(CXCursor cursor) {
+ if (cursor.kind != CXCursor_InclusionDirective)
+ return 0;
+
+ InclusionDirective *ID = getCursorInclusionDirective(cursor);
+ return (void *)ID->getFile();
+}
- SmallVector<CXCursor, 8> Overridden;
- cxcursor::getOverriddenCursors(cursor, Overridden);
+CXSourceRange clang_Cursor_getCommentRange(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return clang_getNullRange();
- // Don't allocate memory if we have no overriden cursors.
- if (Overridden.size() == 0)
- return;
+ const Decl *D = getCursorDecl(C);
+ ASTContext &Context = getCursorContext(C);
+ const RawComment *RC = Context.getRawCommentForAnyRedecl(D);
+ if (!RC)
+ return clang_getNullRange();
- *num_overridden = Overridden.size();
- *overridden = new CXCursor [Overridden.size()];
- std::copy(Overridden.begin(), Overridden.end(), *overridden);
+ return cxloc::translateSourceRange(Context, RC->getSourceRange());
}
-void clang_disposeOverriddenCursors(CXCursor *overridden) {
- delete [] overridden;
+CXString clang_Cursor_getRawCommentText(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return createCXString((const char *) NULL);
+
+ const Decl *D = getCursorDecl(C);
+ ASTContext &Context = getCursorContext(C);
+ const RawComment *RC = Context.getRawCommentForAnyRedecl(D);
+ StringRef RawText = RC ? RC->getRawText(Context.getSourceManager()) :
+ StringRef();
+
+ // Don't duplicate the string because RawText points directly into source
+ // code.
+ return createCXString(RawText, false);
}
-CXFile clang_getIncludedFile(CXCursor cursor) {
- if (cursor.kind != CXCursor_InclusionDirective)
- return 0;
-
- InclusionDirective *ID = getCursorInclusionDirective(cursor);
- return (void *)ID->getFile();
+CXString clang_Cursor_getBriefCommentText(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return createCXString((const char *) NULL);
+
+ const Decl *D = getCursorDecl(C);
+ const ASTContext &Context = getCursorContext(C);
+ const RawComment *RC = Context.getRawCommentForAnyRedecl(D);
+
+ if (RC) {
+ StringRef BriefText = RC->getBriefText(Context);
+
+ // Don't duplicate the string because RawComment ensures that this memory
+ // will not go away.
+ return createCXString(BriefText, false);
+ }
+
+ return createCXString((const char *) NULL);
}
-
-} // end: extern "C"
+CXComment clang_Cursor_getParsedComment(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return cxcomment::createCXComment(NULL);
+
+ const Decl *D = getCursorDecl(C);
+ const ASTContext &Context = getCursorContext(C);
+ const comments::FullComment *FC = Context.getCommentForDecl(D);
+
+ return cxcomment::createCXComment(FC);
+}
+
+} // end: extern "C"
//===----------------------------------------------------------------------===//
// C++ AST instrospection.
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 303fb1f..0073b50 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -227,6 +227,17 @@ clang_getCompletionParent(CXCompletionString completion_string,
*kind = CCStr->getParentContextKind();
return createCXString(CCStr->getParentContextName(), /*DupString=*/false);
}
+
+CXString
+clang_getCompletionBriefComment(CXCompletionString completion_string) {
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+
+ if (!CCStr)
+ return createCXString((const char *) NULL);
+
+ return createCXString(CCStr->getBriefComment(), /*DupString=*/false);
+}
+
/// \brief The CXCodeCompleteResults structure we allocate internally;
/// the client only sees the initial CXCodeCompleteResults structure.
@@ -509,9 +520,10 @@ namespace {
SmallVector<CXCompletionResult, 16> StoredResults;
CXTranslationUnit *TU;
public:
- CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results,
+ CaptureCompletionResults(const CodeCompleteOptions &Opts,
+ AllocatedCXCodeCompleteResults &Results,
CXTranslationUnit *TranslationUnit)
- : CodeCompleteConsumer(true, false, true, false),
+ : CodeCompleteConsumer(Opts, false),
AllocatedResults(Results), CCTUInfo(Results.CodeCompletionAllocator),
TU(TranslationUnit) { }
~CaptureCompletionResults() { Finish(); }
@@ -524,7 +536,8 @@ namespace {
for (unsigned I = 0; I != NumResults; ++I) {
CodeCompletionString *StoredCompletion
= Results[I].CreateCodeCompletionString(S, getAllocator(),
- getCodeCompletionTUInfo());
+ getCodeCompletionTUInfo(),
+ includeBriefComments());
CXCompletionResult R;
R.CursorKind = Results[I].CursorKind;
@@ -658,6 +671,7 @@ void clang_codeCompleteAt_Impl(void *UserData) {
struct CXUnsavedFile *unsaved_files = CCAI->unsaved_files;
unsigned num_unsaved_files = CCAI->num_unsaved_files;
unsigned options = CCAI->options;
+ bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments;
CCAI->result = 0;
#ifdef UDP_CODE_COMPLETION_LOGGER
@@ -699,13 +713,16 @@ void clang_codeCompleteAt_Impl(void *UserData) {
Results->NumResults = 0;
// Create a code-completion consumer to capture the results.
- CaptureCompletionResults Capture(*Results, &TU);
+ CodeCompleteOptions Opts;
+ Opts.IncludeBriefComments = IncludeBriefComments;
+ CaptureCompletionResults Capture(Opts, *Results, &TU);
// Perform completion.
AST->CodeComplete(complete_filename, complete_line, complete_column,
RemappedFiles.data(), RemappedFiles.size(),
(options & CXCodeComplete_IncludeMacros),
(options & CXCodeComplete_IncludeCodePatterns),
+ IncludeBriefComments,
Capture,
*Results->Diag, Results->LangOpts, *Results->SourceMgr,
*Results->FileMgr, Results->Diagnostics,
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 8fbe3d8..14722e0 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -86,11 +86,10 @@ public:
class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
public:
- CXDiagnosticRenderer(const SourceManager &SM,
- const LangOptions &LangOpts,
+ CXDiagnosticRenderer(const LangOptions &LangOpts,
const DiagnosticOptions &DiagOpts,
CXDiagnosticSetImpl *mainSet)
- : DiagnosticNoteRenderer(SM, LangOpts, DiagOpts),
+ : DiagnosticNoteRenderer(LangOpts, DiagOpts),
CurrentSet(mainSet), MainSet(mainSet) {}
virtual ~CXDiagnosticRenderer() {}
@@ -116,26 +115,38 @@ public:
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<CharSourceRange> Ranges,
+ const SourceManager *SM,
DiagOrStoredDiag D) {
if (!D.isNull())
return;
- CXSourceLocation L = translateSourceLocation(SM, LangOpts, Loc);
+ CXSourceLocation L;
+ if (SM)
+ L = translateSourceLocation(*SM, LangOpts, Loc);
+ else
+ L = clang_getNullLocation();
CXDiagnosticImpl *CD = new CXDiagnosticCustomNoteImpl(Message, L);
CurrentSet->appendDiagnostic(CD);
}
virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges) {}
+ ArrayRef<CharSourceRange> Ranges,
+ const SourceManager &SM) {}
virtual void emitCodeContext(SourceLocation Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints) {}
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) {}
- virtual void emitNote(SourceLocation Loc, StringRef Message) {
- CXSourceLocation L = translateSourceLocation(SM, LangOpts, Loc);
+ virtual void emitNote(SourceLocation Loc, StringRef Message,
+ const SourceManager *SM) {
+ CXSourceLocation L;
+ if (SM)
+ L = translateSourceLocation(*SM, LangOpts, Loc);
+ else
+ L = clang_getNullLocation();
CurrentSet->appendDiagnostic(new CXDiagnosticCustomNoteImpl(Message,
L));
}
@@ -181,8 +192,7 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
TU->Diagnostics = Set;
DiagnosticOptions DOpts;
- CXDiagnosticRenderer Renderer(AU->getSourceManager(),
- AU->getASTContext().getLangOpts(),
+ CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
DOpts, Set);
for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 7c79b69..c885dd5 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -754,7 +754,7 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
case TemplateArgument::Integral:
Out << 'V';
VisitType(Arg.getIntegralType());
- Out << *Arg.getAsIntegral();
+ Out << Arg.getAsIntegral();
break;
}
}
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index fb0b91f..283276f 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -1,16 +1,6 @@
-set(LLVM_USED_LIBS
- clangARCMigrate
- clangRewrite
- clangFrontend
- clangDriver
- clangSerialization
- clangSema
- clangEdit
- clangAST
- clangLex
- clangBasic)
-
-set( LLVM_LINK_COMPONENTS
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
support
mc
)
@@ -27,8 +17,10 @@ set(SOURCES
CIndexUSRs.cpp
CIndexer.cpp
CIndexer.h
+ CXComment.cpp
CXCursor.cpp
CXCursor.h
+ CXCompilationDatabase.cpp
CXLoadedDiagnostic.cpp
CXLoadedDiagnostic.h
CXSourceLocation.cpp
@@ -49,32 +41,60 @@ set(SOURCES
../../include/clang-c/Index.h
)
+set(LIBRARIES
+ clangARCMigrate
+ clangRewrite
+ clangFrontend
+ clangDriver
+ clangSerialization
+ clangSema
+ clangEdit
+ clangAST
+ clangLex
+ clangTooling
+ clangBasic
+ )
+
+set(GENERATED_HEADERS
+ ClangAttrClasses
+ ClangAttrList
+ ClangAttrParsedAttrList
+ ClangCommentNodes
+ ClangDiagnosticCommon
+ ClangDiagnosticFrontend
+ ClangDeclNodes
+ ClangStmtNodes
+ )
+
if( LLVM_ENABLE_PIC )
set(SHARED_LIBRARY TRUE)
add_clang_library(libclang ${SOURCES})
+ target_link_libraries(libclang ${LIBRARIES})
+ add_dependencies(libclang ${GENERATED_HEADERS})
- set_target_properties(libclang
- PROPERTIES
- OUTPUT_NAME "libclang"
- VERSION ${LIBCLANG_LIBRARY_VERSION}
- DEFINE_SYMBOL _CINDEX_LIB_)
+ if(WIN32)
+ set_target_properties(libclang
+ PROPERTIES
+ OUTPUT_NAME "libclang"
+ VERSION ${LIBCLANG_LIBRARY_VERSION}
+ DEFINE_SYMBOL _CINDEX_LIB_)
+ else()
+ set_target_properties(libclang
+ PROPERTIES
+ OUTPUT_NAME "clang"
+ VERSION ${LIBCLANG_LIBRARY_VERSION}
+ DEFINE_SYMBOL _CINDEX_LIB_)
+ endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LIBCLANG_LINK_FLAGS
- "-Wl,-compatibility_version -Wl,1 -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000")
+ "-Wl,-compatibility_version -Wl,1 -Wl,-dead_strip")
set_target_properties(libclang
PROPERTIES
LINK_FLAGS "${LIBCLANG_LINK_FLAGS}"
INSTALL_NAME_DIR "@executable_path/../lib")
endif()
- if(MSVC)
- # windows.h doesn't compile with /Za
- get_target_property(NON_ANSI_COMPILE_FLAGS libclang COMPILE_FLAGS)
- string(REPLACE "/Za" "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
- set_target_properties(libclang PROPERTIES
- COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
- endif()
set(LIBCLANG_STATIC_TARGET_NAME libclang_static)
else()
@@ -83,8 +103,10 @@ endif()
if( NOT BUILD_SHARED_LIBS AND NOT WIN32 )
add_clang_library(${LIBCLANG_STATIC_TARGET_NAME} STATIC ${SOURCES})
+ target_link_libraries(${LIBCLANG_STATIC_TARGET_NAME} ${LIBRARIES})
+ add_dependencies(${LIBCLANG_STATIC_TARGET_NAME} ${GENERATED_HEADERS})
set_target_properties(${LIBCLANG_STATIC_TARGET_NAME}
PROPERTIES
- OUTPUT_NAME "libclang")
+ OUTPUT_NAME "clang")
endif()
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
new file mode 100644
index 0000000..c5c9ca8
--- /dev/null
+++ b/tools/libclang/CXComment.cpp
@@ -0,0 +1,1230 @@
+//===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines all libclang APIs related to walking comment AST.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang-c/Index.h"
+#include "CXString.h"
+#include "CXComment.h"
+#include "CXCursor.h"
+#include "CXTranslationUnit.h"
+
+#include "clang/AST/CommentVisitor.h"
+#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/Decl.h"
+#include "clang/Frontend/ASTUnit.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <climits>
+
+using namespace clang;
+using namespace clang::cxstring;
+using namespace clang::comments;
+using namespace clang::cxcomment;
+
+extern "C" {
+
+enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
+ const Comment *C = getASTNode(CXC);
+ if (!C)
+ return CXComment_Null;
+
+ switch (C->getCommentKind()) {
+ case Comment::NoCommentKind:
+ return CXComment_Null;
+
+ case Comment::TextCommentKind:
+ return CXComment_Text;
+
+ case Comment::InlineCommandCommentKind:
+ return CXComment_InlineCommand;
+
+ case Comment::HTMLStartTagCommentKind:
+ return CXComment_HTMLStartTag;
+
+ case Comment::HTMLEndTagCommentKind:
+ return CXComment_HTMLEndTag;
+
+ case Comment::ParagraphCommentKind:
+ return CXComment_Paragraph;
+
+ case Comment::BlockCommandCommentKind:
+ return CXComment_BlockCommand;
+
+ case Comment::ParamCommandCommentKind:
+ return CXComment_ParamCommand;
+
+ case Comment::TParamCommandCommentKind:
+ return CXComment_TParamCommand;
+
+ case Comment::VerbatimBlockCommentKind:
+ return CXComment_VerbatimBlockCommand;
+
+ case Comment::VerbatimBlockLineCommentKind:
+ return CXComment_VerbatimBlockLine;
+
+ case Comment::VerbatimLineCommentKind:
+ return CXComment_VerbatimLine;
+
+ case Comment::FullCommentKind:
+ return CXComment_FullComment;
+ }
+ llvm_unreachable("unknown CommentKind");
+}
+
+unsigned clang_Comment_getNumChildren(CXComment CXC) {
+ const Comment *C = getASTNode(CXC);
+ if (!C)
+ return 0;
+
+ return C->child_count();
+}
+
+CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
+ const Comment *C = getASTNode(CXC);
+ if (!C || ChildIdx >= C->child_count())
+ return createCXComment(NULL);
+
+ return createCXComment(*(C->child_begin() + ChildIdx));
+}
+
+unsigned clang_Comment_isWhitespace(CXComment CXC) {
+ const Comment *C = getASTNode(CXC);
+ if (!C)
+ return false;
+
+ if (const TextComment *TC = dyn_cast<TextComment>(C))
+ return TC->isWhitespace();
+
+ if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
+ return PC->isWhitespace();
+
+ return false;
+}
+
+unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
+ const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
+ if (!ICC)
+ return false;
+
+ return ICC->hasTrailingNewline();
+}
+
+CXString clang_TextComment_getText(CXComment CXC) {
+ const TextComment *TC = getASTNodeAs<TextComment>(CXC);
+ if (!TC)
+ return createCXString((const char *) 0);
+
+ return createCXString(TC->getText(), /*DupString=*/ false);
+}
+
+CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
+ const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
+ if (!ICC)
+ return createCXString((const char *) 0);
+
+ return createCXString(ICC->getCommandName(), /*DupString=*/ false);
+}
+
+enum CXCommentInlineCommandRenderKind
+clang_InlineCommandComment_getRenderKind(CXComment CXC) {
+ const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
+ if (!ICC)
+ return CXCommentInlineCommandRenderKind_Normal;
+
+ switch (ICC->getRenderKind()) {
+ case InlineCommandComment::RenderNormal:
+ return CXCommentInlineCommandRenderKind_Normal;
+
+ case InlineCommandComment::RenderBold:
+ return CXCommentInlineCommandRenderKind_Bold;
+
+ case InlineCommandComment::RenderMonospaced:
+ return CXCommentInlineCommandRenderKind_Monospaced;
+
+ case InlineCommandComment::RenderEmphasized:
+ return CXCommentInlineCommandRenderKind_Emphasized;
+ }
+ llvm_unreachable("unknown InlineCommandComment::RenderKind");
+}
+
+unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
+ const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
+ if (!ICC)
+ return 0;
+
+ return ICC->getNumArgs();
+}
+
+CXString clang_InlineCommandComment_getArgText(CXComment CXC,
+ unsigned ArgIdx) {
+ const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
+ if (!ICC || ArgIdx >= ICC->getNumArgs())
+ return createCXString((const char *) 0);
+
+ return createCXString(ICC->getArgText(ArgIdx), /*DupString=*/ false);
+}
+
+CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
+ const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
+ if (!HTC)
+ return createCXString((const char *) 0);
+
+ return createCXString(HTC->getTagName(), /*DupString=*/ false);
+}
+
+unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
+ const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
+ if (!HST)
+ return false;
+
+ return HST->isSelfClosing();
+}
+
+unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
+ const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
+ if (!HST)
+ return 0;
+
+ return HST->getNumAttrs();
+}
+
+CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
+ const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
+ if (!HST || AttrIdx >= HST->getNumAttrs())
+ return createCXString((const char *) 0);
+
+ return createCXString(HST->getAttr(AttrIdx).Name, /*DupString=*/ false);
+}
+
+CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
+ const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
+ if (!HST || AttrIdx >= HST->getNumAttrs())
+ return createCXString((const char *) 0);
+
+ return createCXString(HST->getAttr(AttrIdx).Value, /*DupString=*/ false);
+}
+
+CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
+ const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
+ if (!BCC)
+ return createCXString((const char *) 0);
+
+ return createCXString(BCC->getCommandName(), /*DupString=*/ false);
+}
+
+unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
+ const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
+ if (!BCC)
+ return 0;
+
+ return BCC->getNumArgs();
+}
+
+CXString clang_BlockCommandComment_getArgText(CXComment CXC,
+ unsigned ArgIdx) {
+ const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
+ if (!BCC || ArgIdx >= BCC->getNumArgs())
+ return createCXString((const char *) 0);
+
+ return createCXString(BCC->getArgText(ArgIdx), /*DupString=*/ false);
+}
+
+CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
+ const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
+ if (!BCC)
+ return createCXComment(NULL);
+
+ return createCXComment(BCC->getParagraph());
+}
+
+CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
+ const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
+ if (!PCC || !PCC->hasParamName())
+ return createCXString((const char *) 0);
+
+ return createCXString(PCC->getParamName(), /*DupString=*/ false);
+}
+
+unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
+ const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
+ if (!PCC)
+ return false;
+
+ return PCC->isParamIndexValid();
+}
+
+unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
+ const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
+ if (!PCC || !PCC->isParamIndexValid())
+ return ParamCommandComment::InvalidParamIndex;
+
+ return PCC->getParamIndex();
+}
+
+unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
+ const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
+ if (!PCC)
+ return false;
+
+ return PCC->isDirectionExplicit();
+}
+
+enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
+ CXComment CXC) {
+ const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
+ if (!PCC)
+ return CXCommentParamPassDirection_In;
+
+ switch (PCC->getDirection()) {
+ case ParamCommandComment::In:
+ return CXCommentParamPassDirection_In;
+
+ case ParamCommandComment::Out:
+ return CXCommentParamPassDirection_Out;
+
+ case ParamCommandComment::InOut:
+ return CXCommentParamPassDirection_InOut;
+ }
+ llvm_unreachable("unknown ParamCommandComment::PassDirection");
+}
+
+CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
+ const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
+ if (!TPCC || !TPCC->hasParamName())
+ return createCXString((const char *) 0);
+
+ return createCXString(TPCC->getParamName(), /*DupString=*/ false);
+}
+
+unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
+ const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
+ if (!TPCC)
+ return false;
+
+ return TPCC->isPositionValid();
+}
+
+unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
+ const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
+ if (!TPCC || !TPCC->isPositionValid())
+ return 0;
+
+ return TPCC->getDepth();
+}
+
+unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
+ const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
+ if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
+ return 0;
+
+ return TPCC->getIndex(Depth);
+}
+
+CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
+ const VerbatimBlockLineComment *VBL =
+ getASTNodeAs<VerbatimBlockLineComment>(CXC);
+ if (!VBL)
+ return createCXString((const char *) 0);
+
+ return createCXString(VBL->getText(), /*DupString=*/ false);
+}
+
+CXString clang_VerbatimLineComment_getText(CXComment CXC) {
+ const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
+ if (!VLC)
+ return createCXString((const char *) 0);
+
+ return createCXString(VLC->getText(), /*DupString=*/ false);
+}
+
+} // end extern "C"
+
+//===----------------------------------------------------------------------===//
+// Helpers for converting comment AST to HTML.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+/// This comparison will sort parameters with valid index by index and
+/// invalid (unresolved) parameters last.
+class ParamCommandCommentCompareIndex {
+public:
+ bool operator()(const ParamCommandComment *LHS,
+ const ParamCommandComment *RHS) const {
+ unsigned LHSIndex = UINT_MAX;
+ unsigned RHSIndex = UINT_MAX;
+ if (LHS->isParamIndexValid())
+ LHSIndex = LHS->getParamIndex();
+ if (RHS->isParamIndexValid())
+ RHSIndex = RHS->getParamIndex();
+
+ return LHSIndex < RHSIndex;
+ }
+};
+
+/// This comparison will sort template parameters in the following order:
+/// \li real template parameters (depth = 1) in index order;
+/// \li all other names (depth > 1);
+/// \li unresolved names.
+class TParamCommandCommentComparePosition {
+public:
+ bool operator()(const TParamCommandComment *LHS,
+ const TParamCommandComment *RHS) const {
+ // Sort unresolved names last.
+ if (!LHS->isPositionValid())
+ return false;
+ if (!RHS->isPositionValid())
+ return true;
+
+ if (LHS->getDepth() > 1)
+ return false;
+ if (RHS->getDepth() > 1)
+ return true;
+
+ // Sort template parameters in index order.
+ if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
+ return LHS->getIndex(0) < RHS->getIndex(0);
+
+ // Leave all other names in source order.
+ return true;
+ }
+};
+
+/// Separate parts of a FullComment.
+struct FullCommentParts {
+ /// Take a full comment apart and initialize members accordingly.
+ FullCommentParts(const FullComment *C);
+
+ const BlockContentComment *Brief;
+ const ParagraphComment *FirstParagraph;
+ const BlockCommandComment *Returns;
+ SmallVector<const ParamCommandComment *, 8> Params;
+ SmallVector<const TParamCommandComment *, 4> TParams;
+ SmallVector<const BlockContentComment *, 8> MiscBlocks;
+};
+
+FullCommentParts::FullCommentParts(const FullComment *C) :
+ Brief(NULL), FirstParagraph(NULL), Returns(NULL) {
+ const CommandTraits Traits;
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ const Comment *Child = *I;
+ if (!Child)
+ continue;
+ switch (Child->getCommentKind()) {
+ case Comment::NoCommentKind:
+ continue;
+
+ case Comment::ParagraphCommentKind: {
+ const ParagraphComment *PC = cast<ParagraphComment>(Child);
+ if (PC->isWhitespace())
+ break;
+ if (!FirstParagraph)
+ FirstParagraph = PC;
+
+ MiscBlocks.push_back(PC);
+ break;
+ }
+
+ case Comment::BlockCommandCommentKind: {
+ const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
+ StringRef CommandName = BCC->getCommandName();
+ if (!Brief && Traits.isBriefCommand(CommandName)) {
+ Brief = BCC;
+ break;
+ }
+ if (!Returns && Traits.isReturnsCommand(CommandName)) {
+ Returns = BCC;
+ break;
+ }
+ MiscBlocks.push_back(BCC);
+ break;
+ }
+
+ case Comment::ParamCommandCommentKind: {
+ const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
+ if (!PCC->hasParamName())
+ break;
+
+ if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
+ break;
+
+ Params.push_back(PCC);
+ break;
+ }
+
+ case Comment::TParamCommandCommentKind: {
+ const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
+ if (!TPCC->hasParamName())
+ break;
+
+ if (!TPCC->hasNonWhitespaceParagraph())
+ break;
+
+ TParams.push_back(TPCC);
+ break;
+ }
+
+ case Comment::VerbatimBlockCommentKind:
+ MiscBlocks.push_back(cast<BlockCommandComment>(Child));
+ break;
+
+ case Comment::VerbatimLineCommentKind: {
+ const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
+ if (!Traits.isDeclarationCommand(VLC->getCommandName()))
+ MiscBlocks.push_back(VLC);
+ break;
+ }
+
+ case Comment::TextCommentKind:
+ case Comment::InlineCommandCommentKind:
+ case Comment::HTMLStartTagCommentKind:
+ case Comment::HTMLEndTagCommentKind:
+ case Comment::VerbatimBlockLineCommentKind:
+ case Comment::FullCommentKind:
+ llvm_unreachable("AST node of this kind can't be a child of "
+ "a FullComment");
+ }
+ }
+
+ // Sort params in order they are declared in the function prototype.
+ // Unresolved parameters are put at the end of the list in the same order
+ // they were seen in the comment.
+ std::stable_sort(Params.begin(), Params.end(),
+ ParamCommandCommentCompareIndex());
+
+ std::stable_sort(TParams.begin(), TParams.end(),
+ TParamCommandCommentComparePosition());
+}
+
+void PrintHTMLStartTagComment(const HTMLStartTagComment *C,
+ llvm::raw_svector_ostream &Result) {
+ Result << "<" << C->getTagName();
+
+ if (C->getNumAttrs() != 0) {
+ for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
+ Result << " ";
+ const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
+ Result << Attr.Name;
+ if (!Attr.Value.empty())
+ Result << "=\"" << Attr.Value << "\"";
+ }
+ }
+
+ if (!C->isSelfClosing())
+ Result << ">";
+ else
+ Result << "/>";
+}
+
+class CommentASTToHTMLConverter :
+ public ConstCommentVisitor<CommentASTToHTMLConverter> {
+public:
+ /// \param Str accumulator for HTML.
+ CommentASTToHTMLConverter(SmallVectorImpl<char> &Str) : Result(Str) { }
+
+ // Inline content.
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+
+ // Block content.
+ void visitParagraphComment(const ParagraphComment *C);
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+
+ void visitFullComment(const FullComment *C);
+
+ // Helpers.
+
+ /// Convert a paragraph that is not a block by itself (an argument to some
+ /// command).
+ void visitNonStandaloneParagraphComment(const ParagraphComment *C);
+
+ void appendToResultWithHTMLEscaping(StringRef S);
+
+private:
+ const CommandTraits Traits;
+
+ /// Output stream for HTML.
+ llvm::raw_svector_ostream Result;
+};
+} // end unnamed namespace
+
+void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
+ appendToResultWithHTMLEscaping(C->getText());
+}
+
+void CommentASTToHTMLConverter::visitInlineCommandComment(
+ const InlineCommandComment *C) {
+ // Nothing to render if no arguments supplied.
+ if (C->getNumArgs() == 0)
+ return;
+
+ // Nothing to render if argument is empty.
+ StringRef Arg0 = C->getArgText(0);
+ if (Arg0.empty())
+ return;
+
+ switch (C->getRenderKind()) {
+ case InlineCommandComment::RenderNormal:
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
+ appendToResultWithHTMLEscaping(C->getArgText(i));
+ Result << " ";
+ }
+ return;
+
+ case InlineCommandComment::RenderBold:
+ assert(C->getNumArgs() == 1);
+ Result << "<b>";
+ appendToResultWithHTMLEscaping(Arg0);
+ Result << "</b>";
+ return;
+ case InlineCommandComment::RenderMonospaced:
+ assert(C->getNumArgs() == 1);
+ Result << "<tt>";
+ appendToResultWithHTMLEscaping(Arg0);
+ Result<< "</tt>";
+ return;
+ case InlineCommandComment::RenderEmphasized:
+ assert(C->getNumArgs() == 1);
+ Result << "<em>";
+ appendToResultWithHTMLEscaping(Arg0);
+ Result << "</em>";
+ return;
+ }
+}
+
+void CommentASTToHTMLConverter::visitHTMLStartTagComment(
+ const HTMLStartTagComment *C) {
+ PrintHTMLStartTagComment(C, Result);
+}
+
+void CommentASTToHTMLConverter::visitHTMLEndTagComment(
+ const HTMLEndTagComment *C) {
+ Result << "</" << C->getTagName() << ">";
+}
+
+void CommentASTToHTMLConverter::visitParagraphComment(
+ const ParagraphComment *C) {
+ if (C->isWhitespace())
+ return;
+
+ Result << "<p>";
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ visit(*I);
+ }
+ Result << "</p>";
+}
+
+void CommentASTToHTMLConverter::visitBlockCommandComment(
+ const BlockCommandComment *C) {
+ StringRef CommandName = C->getCommandName();
+ if (Traits.isBriefCommand(CommandName)) {
+ Result << "<p class=\"para-brief\">";
+ visitNonStandaloneParagraphComment(C->getParagraph());
+ Result << "</p>";
+ return;
+ }
+ if (Traits.isReturnsCommand(CommandName)) {
+ Result << "<p class=\"para-returns\">"
+ "<span class=\"word-returns\">Returns</span> ";
+ visitNonStandaloneParagraphComment(C->getParagraph());
+ Result << "</p>";
+ return;
+ }
+ // We don't know anything about this command. Just render the paragraph.
+ visit(C->getParagraph());
+}
+
+void CommentASTToHTMLConverter::visitParamCommandComment(
+ const ParamCommandComment *C) {
+ if (C->isParamIndexValid()) {
+ Result << "<dt class=\"param-name-index-"
+ << C->getParamIndex()
+ << "\">";
+ } else
+ Result << "<dt class=\"param-name-index-invalid\">";
+
+ appendToResultWithHTMLEscaping(C->getParamName());
+ Result << "</dt>";
+
+ if (C->isParamIndexValid()) {
+ Result << "<dd class=\"param-descr-index-"
+ << C->getParamIndex()
+ << "\">";
+ } else
+ Result << "<dd class=\"param-descr-index-invalid\">";
+
+ visitNonStandaloneParagraphComment(C->getParagraph());
+ Result << "</dd>";
+}
+
+void CommentASTToHTMLConverter::visitTParamCommandComment(
+ const TParamCommandComment *C) {
+ if (C->isPositionValid()) {
+ if (C->getDepth() == 1)
+ Result << "<dt class=\"tparam-name-index-"
+ << C->getIndex(0)
+ << "\">";
+ else
+ Result << "<dt class=\"tparam-name-index-other\">";
+ } else
+ Result << "<dt class=\"tparam-name-index-invalid\">";
+
+ appendToResultWithHTMLEscaping(C->getParamName());
+ Result << "</dt>";
+
+ if (C->isPositionValid()) {
+ if (C->getDepth() == 1)
+ Result << "<dd class=\"tparam-descr-index-"
+ << C->getIndex(0)
+ << "\">";
+ else
+ Result << "<dd class=\"tparam-descr-index-other\">";
+ } else
+ Result << "<dd class=\"tparam-descr-index-invalid\">";
+
+ visitNonStandaloneParagraphComment(C->getParagraph());
+ Result << "</dd>";
+}
+
+void CommentASTToHTMLConverter::visitVerbatimBlockComment(
+ const VerbatimBlockComment *C) {
+ unsigned NumLines = C->getNumLines();
+ if (NumLines == 0)
+ return;
+
+ Result << "<pre>";
+ for (unsigned i = 0; i != NumLines; ++i) {
+ appendToResultWithHTMLEscaping(C->getText(i));
+ if (i + 1 != NumLines)
+ Result << '\n';
+ }
+ Result << "</pre>";
+}
+
+void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ llvm_unreachable("should not see this AST node");
+}
+
+void CommentASTToHTMLConverter::visitVerbatimLineComment(
+ const VerbatimLineComment *C) {
+ Result << "<pre>";
+ appendToResultWithHTMLEscaping(C->getText());
+ Result << "</pre>";
+}
+
+void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
+ FullCommentParts Parts(C);
+
+ bool FirstParagraphIsBrief = false;
+ if (Parts.Brief)
+ visit(Parts.Brief);
+ else if (Parts.FirstParagraph) {
+ Result << "<p class=\"para-brief\">";
+ visitNonStandaloneParagraphComment(Parts.FirstParagraph);
+ Result << "</p>";
+ FirstParagraphIsBrief = true;
+ }
+
+ for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
+ const Comment *C = Parts.MiscBlocks[i];
+ if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
+ continue;
+ visit(C);
+ }
+
+ if (Parts.TParams.size() != 0) {
+ Result << "<dl>";
+ for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
+ visit(Parts.TParams[i]);
+ Result << "</dl>";
+ }
+
+ if (Parts.Params.size() != 0) {
+ Result << "<dl>";
+ for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
+ visit(Parts.Params[i]);
+ Result << "</dl>";
+ }
+
+ if (Parts.Returns)
+ visit(Parts.Returns);
+
+ Result.flush();
+}
+
+void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
+ const ParagraphComment *C) {
+ if (!C)
+ return;
+
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ visit(*I);
+ }
+}
+
+void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
+ for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
+ const char C = *I;
+ switch (C) {
+ case '&':
+ Result << "&amp;";
+ break;
+ case '<':
+ Result << "&lt;";
+ break;
+ case '>':
+ Result << "&gt;";
+ break;
+ case '"':
+ Result << "&quot;";
+ break;
+ case '\'':
+ Result << "&#39;";
+ break;
+ case '/':
+ Result << "&#47;";
+ break;
+ default:
+ Result << C;
+ break;
+ }
+ }
+}
+
+extern "C" {
+
+CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
+ const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
+ if (!HTC)
+ return createCXString((const char *) 0);
+
+ SmallString<128> HTML;
+ CommentASTToHTMLConverter Converter(HTML);
+ Converter.visit(HTC);
+ return createCXString(HTML.str(), /* DupString = */ true);
+}
+
+CXString clang_FullComment_getAsHTML(CXComment CXC) {
+ const FullComment *FC = getASTNodeAs<FullComment>(CXC);
+ if (!FC)
+ return createCXString((const char *) 0);
+
+ SmallString<1024> HTML;
+ CommentASTToHTMLConverter Converter(HTML);
+ Converter.visit(FC);
+ return createCXString(HTML.str(), /* DupString = */ true);
+}
+
+} // end extern "C"
+
+namespace {
+class CommentASTToXMLConverter :
+ public ConstCommentVisitor<CommentASTToXMLConverter> {
+public:
+ /// \param Str accumulator for XML.
+ CommentASTToXMLConverter(const SourceManager &SM,
+ SmallVectorImpl<char> &Str) :
+ SM(SM), Result(Str) { }
+
+ // Inline content.
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+
+ // Block content.
+ void visitParagraphComment(const ParagraphComment *C);
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+
+ void visitFullComment(const FullComment *C);
+
+ // Helpers.
+ void appendToResultWithXMLEscaping(StringRef S);
+
+private:
+ const SourceManager &SM;
+
+ /// Output stream for XML.
+ llvm::raw_svector_ostream Result;
+};
+} // end unnamed namespace
+
+void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
+ appendToResultWithXMLEscaping(C->getText());
+}
+
+void CommentASTToXMLConverter::visitInlineCommandComment(const InlineCommandComment *C) {
+ // Nothing to render if no arguments supplied.
+ if (C->getNumArgs() == 0)
+ return;
+
+ // Nothing to render if argument is empty.
+ StringRef Arg0 = C->getArgText(0);
+ if (Arg0.empty())
+ return;
+
+ switch (C->getRenderKind()) {
+ case InlineCommandComment::RenderNormal:
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
+ appendToResultWithXMLEscaping(C->getArgText(i));
+ Result << " ";
+ }
+ return;
+ case InlineCommandComment::RenderBold:
+ assert(C->getNumArgs() == 1);
+ Result << "<bold>";
+ appendToResultWithXMLEscaping(Arg0);
+ Result << "</bold>";
+ return;
+ case InlineCommandComment::RenderMonospaced:
+ assert(C->getNumArgs() == 1);
+ Result << "<monospaced>";
+ appendToResultWithXMLEscaping(Arg0);
+ Result << "</monospaced>";
+ return;
+ case InlineCommandComment::RenderEmphasized:
+ assert(C->getNumArgs() == 1);
+ Result << "<emphasized>";
+ appendToResultWithXMLEscaping(Arg0);
+ Result << "</emphasized>";
+ return;
+ }
+}
+
+void CommentASTToXMLConverter::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
+ Result << "<rawHTML><![CDATA[";
+ PrintHTMLStartTagComment(C, Result);
+ Result << "]]></rawHTML>";
+}
+
+void CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
+ Result << "<rawHTML>&lt;/" << C->getTagName() << "&gt;</rawHTML>";
+}
+
+void CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
+ if (C->isWhitespace())
+ return;
+
+ Result << "<Para>";
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ visit(*I);
+ }
+ Result << "</Para>";
+}
+
+void CommentASTToXMLConverter::visitBlockCommandComment(const BlockCommandComment *C) {
+ visit(C->getParagraph());
+}
+
+void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandComment *C) {
+ Result << "<Parameter><Name>";
+ appendToResultWithXMLEscaping(C->getParamName());
+ Result << "</Name>";
+
+ if (C->isParamIndexValid())
+ Result << "<Index>" << C->getParamIndex() << "</Index>";
+
+ Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
+ switch (C->getDirection()) {
+ case ParamCommandComment::In:
+ Result << "in";
+ break;
+ case ParamCommandComment::Out:
+ Result << "out";
+ break;
+ case ParamCommandComment::InOut:
+ Result << "in,out";
+ break;
+ }
+ Result << "</Direction><Discussion>";
+ visit(C->getParagraph());
+ Result << "</Discussion></Parameter>";
+}
+
+void CommentASTToXMLConverter::visitTParamCommandComment(
+ const TParamCommandComment *C) {
+ Result << "<Parameter><Name>";
+ appendToResultWithXMLEscaping(C->getParamName());
+ Result << "</Name>";
+
+ if (C->isPositionValid() && C->getDepth() == 1) {
+ Result << "<Index>" << C->getIndex(0) << "</Index>";
+ }
+
+ Result << "<Discussion>";
+ visit(C->getParagraph());
+ Result << "</Discussion></Parameter>";
+}
+
+void CommentASTToXMLConverter::visitVerbatimBlockComment(
+ const VerbatimBlockComment *C) {
+ unsigned NumLines = C->getNumLines();
+ if (NumLines == 0)
+ return;
+
+ Result << llvm::StringSwitch<const char *>(C->getCommandName())
+ .Case("code", "<Verbatim xml:space=\"preserve\" kind=\"code\">")
+ .Default("<Verbatim xml:space=\"preserve\" kind=\"verbatim\">");
+ for (unsigned i = 0; i != NumLines; ++i) {
+ appendToResultWithXMLEscaping(C->getText(i));
+ if (i + 1 != NumLines)
+ Result << '\n';
+ }
+ Result << "</Verbatim>";
+}
+
+void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ llvm_unreachable("should not see this AST node");
+}
+
+void CommentASTToXMLConverter::visitVerbatimLineComment(
+ const VerbatimLineComment *C) {
+ Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
+ appendToResultWithXMLEscaping(C->getText());
+ Result << "</Verbatim>";
+}
+
+void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
+ FullCommentParts Parts(C);
+
+ const DeclInfo *DI = C->getDeclInfo();
+ StringRef RootEndTag;
+ if (DI) {
+ switch (DI->getKind()) {
+ case DeclInfo::OtherKind:
+ RootEndTag = "</Other>";
+ Result << "<Other";
+ break;
+ case DeclInfo::FunctionKind:
+ RootEndTag = "</Function>";
+ Result << "<Function";
+ switch (DI->TemplateKind) {
+ case DeclInfo::NotTemplate:
+ break;
+ case DeclInfo::Template:
+ Result << " templateKind=\"template\"";
+ break;
+ case DeclInfo::TemplateSpecialization:
+ Result << " templateKind=\"specialization\"";
+ break;
+ case DeclInfo::TemplatePartialSpecialization:
+ llvm_unreachable("partial specializations of functions "
+ "are not allowed in C++");
+ }
+ if (DI->IsInstanceMethod)
+ Result << " isInstanceMethod=\"1\"";
+ if (DI->IsClassMethod)
+ Result << " isClassMethod=\"1\"";
+ break;
+ case DeclInfo::ClassKind:
+ RootEndTag = "</Class>";
+ Result << "<Class";
+ switch (DI->TemplateKind) {
+ case DeclInfo::NotTemplate:
+ break;
+ case DeclInfo::Template:
+ Result << " templateKind=\"template\"";
+ break;
+ case DeclInfo::TemplateSpecialization:
+ Result << " templateKind=\"specialization\"";
+ break;
+ case DeclInfo::TemplatePartialSpecialization:
+ Result << " templateKind=\"partialSpecialization\"";
+ break;
+ }
+ break;
+ case DeclInfo::VariableKind:
+ RootEndTag = "</Variable>";
+ Result << "<Variable";
+ break;
+ case DeclInfo::NamespaceKind:
+ RootEndTag = "</Namespace>";
+ Result << "<Namespace";
+ break;
+ case DeclInfo::TypedefKind:
+ RootEndTag = "</Typedef>";
+ Result << "<Typedef";
+ break;
+ case DeclInfo::EnumKind:
+ RootEndTag = "</Enum>";
+ Result << "<Enum";
+ break;
+ }
+
+ {
+ // Print line and column number.
+ SourceLocation Loc = DI->ThisDecl->getLocation();
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ if (!FID.isInvalid()) {
+ if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
+ Result << " file=\"";
+ appendToResultWithXMLEscaping(FE->getName());
+ Result << "\"";
+ }
+ Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
+ << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
+ << "\"";
+ }
+ }
+
+ // Finish the root tag.
+ Result << ">";
+
+ bool FoundName = false;
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->ThisDecl)) {
+ if (DeclarationName DeclName = ND->getDeclName()) {
+ Result << "<Name>";
+ std::string Name = DeclName.getAsString();
+ appendToResultWithXMLEscaping(Name);
+ FoundName = true;
+ Result << "</Name>";
+ }
+ }
+ if (!FoundName)
+ Result << "<Name>&lt;anonymous&gt;</Name>";
+
+ {
+ // Print USR.
+ SmallString<128> USR;
+ cxcursor::getDeclCursorUSR(DI->ThisDecl, USR);
+ if (!USR.empty()) {
+ Result << "<USR>";
+ appendToResultWithXMLEscaping(USR);
+ Result << "</USR>";
+ }
+ }
+ } else {
+ // No DeclInfo -- just emit some root tag and name tag.
+ RootEndTag = "</Other>";
+ Result << "<Other><Name>unknown</Name>";
+ }
+
+ bool FirstParagraphIsBrief = false;
+ if (Parts.Brief) {
+ Result << "<Abstract>";
+ visit(Parts.Brief);
+ Result << "</Abstract>";
+ } else if (Parts.FirstParagraph) {
+ Result << "<Abstract>";
+ visit(Parts.FirstParagraph);
+ Result << "</Abstract>";
+ FirstParagraphIsBrief = true;
+ }
+
+ if (Parts.TParams.size() != 0) {
+ Result << "<TemplateParameters>";
+ for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
+ visit(Parts.TParams[i]);
+ Result << "</TemplateParameters>";
+ }
+
+ if (Parts.Params.size() != 0) {
+ Result << "<Parameters>";
+ for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
+ visit(Parts.Params[i]);
+ Result << "</Parameters>";
+ }
+
+ if (Parts.Returns) {
+ Result << "<ResultDiscussion>";
+ visit(Parts.Returns);
+ Result << "</ResultDiscussion>";
+ }
+
+ {
+ bool StartTagEmitted = false;
+ for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
+ const Comment *C = Parts.MiscBlocks[i];
+ if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
+ continue;
+ if (!StartTagEmitted) {
+ Result << "<Discussion>";
+ StartTagEmitted = true;
+ }
+ visit(C);
+ }
+ if (StartTagEmitted)
+ Result << "</Discussion>";
+ }
+
+ Result << RootEndTag;
+
+ Result.flush();
+}
+
+void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
+ for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
+ const char C = *I;
+ switch (C) {
+ case '&':
+ Result << "&amp;";
+ break;
+ case '<':
+ Result << "&lt;";
+ break;
+ case '>':
+ Result << "&gt;";
+ break;
+ case '"':
+ Result << "&quot;";
+ break;
+ case '\'':
+ Result << "&apos;";
+ break;
+ default:
+ Result << C;
+ break;
+ }
+ }
+}
+
+extern "C" {
+
+CXString clang_FullComment_getAsXML(CXTranslationUnit TU, CXComment CXC) {
+ const FullComment *FC = getASTNodeAs<FullComment>(CXC);
+ if (!FC)
+ return createCXString((const char *) 0);
+
+ SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager();
+
+ SmallString<1024> XML;
+ CommentASTToXMLConverter Converter(SM, XML);
+ Converter.visit(FC);
+ return createCXString(XML.str(), /* DupString = */ true);
+}
+
+} // end extern "C"
+
diff --git a/tools/libclang/CXComment.h b/tools/libclang/CXComment.h
new file mode 100644
index 0000000..753877e
--- /dev/null
+++ b/tools/libclang/CXComment.h
@@ -0,0 +1,47 @@
+//===- CXComment.h - Routines for manipulating CXComments -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines routines for manipulating CXComments.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CXCOMMENT_H
+#define LLVM_CLANG_CXCOMMENT_H
+
+#include "clang-c/Index.h"
+
+#include "clang/AST/Comment.h"
+
+namespace clang {
+namespace cxcomment {
+
+inline CXComment createCXComment(const comments::Comment *C) {
+ CXComment Result;
+ Result.Data = C;
+ return Result;
+}
+
+inline const comments::Comment *getASTNode(CXComment CXC) {
+ return static_cast<const comments::Comment *>(CXC.Data);
+}
+
+template<typename T>
+inline const T *getASTNodeAs(CXComment CXC) {
+ const comments::Comment *C = getASTNode(CXC);
+ if (!C)
+ return NULL;
+
+ return dyn_cast<T>(C);
+}
+
+} // end namespace cxcomment
+} // end namespace clang
+
+#endif
+
diff --git a/tools/libclang/CXCompilationDatabase.cpp b/tools/libclang/CXCompilationDatabase.cpp
new file mode 100644
index 0000000..7bd319a
--- /dev/null
+++ b/tools/libclang/CXCompilationDatabase.cpp
@@ -0,0 +1,129 @@
+#include "clang-c/CXCompilationDatabase.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "CXString.h"
+
+using namespace clang;
+using namespace clang::tooling;
+using namespace clang::cxstring;
+
+extern "C" {
+
+// FIXME: do something more usefull with the error message
+CXCompilationDatabase
+clang_CompilationDatabase_fromDirectory(const char *BuildDir,
+ CXCompilationDatabase_Error *ErrorCode)
+{
+ std::string ErrorMsg;
+ CXCompilationDatabase_Error Err = CXCompilationDatabase_NoError;
+
+ CompilationDatabase *db = CompilationDatabase::loadFromDirectory(BuildDir,
+ ErrorMsg);
+
+ if (!db) {
+ fprintf(stderr, "LIBCLANG TOOLING ERROR: %s\n", ErrorMsg.c_str());
+ Err = CXCompilationDatabase_CanNotLoadDatabase;
+ }
+
+ if (ErrorCode)
+ *ErrorCode = Err;
+
+ return db;
+}
+
+void
+clang_CompilationDatabase_dispose(CXCompilationDatabase CDb)
+{
+ delete static_cast<CompilationDatabase *>(CDb);
+}
+
+struct AllocatedCXCompileCommands
+{
+ std::vector<CompileCommand> CCmd;
+
+ AllocatedCXCompileCommands(const std::vector<CompileCommand>& Cmd)
+ : CCmd(Cmd)
+ { }
+};
+
+CXCompileCommands
+clang_CompilationDatabase_getCompileCommands(CXCompilationDatabase CDb,
+ const char *CompleteFileName)
+{
+ if (CompilationDatabase *db = static_cast<CompilationDatabase *>(CDb)) {
+ const std::vector<CompileCommand>
+ CCmd(db->getCompileCommands(CompleteFileName));
+ if (!CCmd.empty())
+ return new AllocatedCXCompileCommands( CCmd );
+ }
+
+ return 0;
+}
+
+void
+clang_CompileCommands_dispose(CXCompileCommands Cmds)
+{
+ delete static_cast<AllocatedCXCompileCommands *>(Cmds);
+}
+
+unsigned
+clang_CompileCommands_getSize(CXCompileCommands Cmds)
+{
+ if (!Cmds)
+ return 0;
+
+ AllocatedCXCompileCommands *ACC =
+ static_cast<AllocatedCXCompileCommands *>(Cmds);
+
+ return ACC->CCmd.size();
+}
+
+CXCompileCommand
+clang_CompileCommands_getCommand(CXCompileCommands Cmds, unsigned I)
+{
+ if (!Cmds)
+ return 0;
+
+ AllocatedCXCompileCommands *ACC =
+ static_cast<AllocatedCXCompileCommands *>(Cmds);
+
+ if (I >= ACC->CCmd.size())
+ return 0;
+
+ return &ACC->CCmd[I];
+}
+
+CXString
+clang_CompileCommand_getDirectory(CXCompileCommand CCmd)
+{
+ if (!CCmd)
+ return createCXString((const char*)NULL);
+
+ CompileCommand *cmd = static_cast<CompileCommand *>(CCmd);
+ return createCXString(cmd->Directory);
+}
+
+unsigned
+clang_CompileCommand_getNumArgs(CXCompileCommand CCmd)
+{
+ if (!CCmd)
+ return 0;
+
+ return static_cast<CompileCommand *>(CCmd)->CommandLine.size();
+}
+
+CXString
+clang_CompileCommand_getArg(CXCompileCommand CCmd, unsigned Arg)
+{
+ if (!CCmd)
+ return createCXString((const char*)NULL);
+
+ CompileCommand *Cmd = static_cast<CompileCommand *>(CCmd);
+
+ if (Arg >= Cmd->CommandLine.size())
+ return createCXString((const char*)NULL);
+
+ return createCXString(Cmd->CommandLine[Arg]);
+}
+
+
+} // end: extern "C"
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index a298759..2757af4 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -30,9 +30,9 @@
using namespace clang;
using namespace cxcursor;
-CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) {
+CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K, CXTranslationUnit TU) {
assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid);
- CXCursor C = { K, 0, { 0, 0, 0 } };
+ CXCursor C = { K, 0, { 0, 0, TU } };
return C;
}
@@ -148,6 +148,10 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::AsmStmtClass:
K = CXCursor_AsmStmt;
break;
+
+ case Stmt::MSAsmStmtClass:
+ K = CXCursor_MSAsmStmt;
+ break;
case Stmt::ObjCAtTryStmtClass:
K = CXCursor_ObjCAtTryStmt;
@@ -229,7 +233,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::VAArgExprClass:
case Stmt::ObjCArrayLiteralClass:
case Stmt::ObjCDictionaryLiteralClass:
- case Stmt::ObjCNumericLiteralClass:
+ case Stmt::ObjCBoxedExprClass:
case Stmt::ObjCSubscriptRefExprClass:
K = CXCursor_UnexposedExpr;
break;
@@ -864,27 +868,10 @@ static inline void CollectOverriddenMethods(CXTranslationUnit TU,
/*MovedToSuper=*/false);
}
-void cxcursor::getOverriddenCursors(CXCursor cursor,
- SmallVectorImpl<CXCursor> &overridden) {
- assert(clang_isDeclaration(cursor.kind));
- Decl *D = getCursorDecl(cursor);
- if (!D)
- return;
-
- // Handle C++ member functions.
- CXTranslationUnit TU = getCursorTU(cursor);
- if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
- for (CXXMethodDecl::method_iterator
- M = CXXMethod->begin_overridden_methods(),
- MEnd = CXXMethod->end_overridden_methods();
- M != MEnd; ++M)
- overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU));
- return;
- }
-
- ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
- if (!Method)
- return;
+static void collectOverriddenMethodsSlow(CXTranslationUnit TU,
+ ObjCMethodDecl *Method,
+ SmallVectorImpl<CXCursor> &overridden) {
+ assert(Method->isOverriding());
if (ObjCProtocolDecl *
ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
@@ -921,6 +908,83 @@ void cxcursor::getOverriddenCursors(CXCursor cursor,
}
}
+static void collectOnCategoriesAfterLocation(SourceLocation Loc,
+ ObjCInterfaceDecl *Class,
+ CXTranslationUnit TU,
+ ObjCMethodDecl *Method,
+ SmallVectorImpl<CXCursor> &Methods) {
+ if (!Class)
+ return;
+
+ SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager();
+ for (ObjCCategoryDecl *Category = Class->getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
+ CollectOverriddenMethodsRecurse(TU, Category, Method, Methods, true);
+
+ collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), TU,
+ Method, Methods);
+}
+
+/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding()
+/// returns false.
+/// You'd think that in that case there are no overrides but categories can
+/// "introduce" new overridden methods that are missed by Sema because the
+/// overrides lookup that it does for methods, inside implementations, will
+/// stop at the interface level (if there is a method there) and not look
+/// further in super classes.
+static void collectOverriddenMethodsFast(CXTranslationUnit TU,
+ ObjCMethodDecl *Method,
+ SmallVectorImpl<CXCursor> &Methods) {
+ assert(!Method->isOverriding());
+
+ ObjCContainerDecl *ContD = cast<ObjCContainerDecl>(Method->getDeclContext());
+ if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD))
+ return;
+ ObjCInterfaceDecl *Class = Method->getClassInterface();
+ if (!Class)
+ return;
+
+ collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(),
+ TU, Method, Methods);
+}
+
+void cxcursor::getOverriddenCursors(CXCursor cursor,
+ SmallVectorImpl<CXCursor> &overridden) {
+ assert(clang_isDeclaration(cursor.kind));
+ Decl *D = getCursorDecl(cursor);
+ if (!D)
+ return;
+
+ // Handle C++ member functions.
+ CXTranslationUnit TU = getCursorTU(cursor);
+ if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
+ for (CXXMethodDecl::method_iterator
+ M = CXXMethod->begin_overridden_methods(),
+ MEnd = CXXMethod->end_overridden_methods();
+ M != MEnd; ++M)
+ overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU));
+ return;
+ }
+
+ ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
+ if (!Method)
+ return;
+
+ if (Method->isRedeclaration()) {
+ Method = cast<ObjCContainerDecl>(Method->getDeclContext())->
+ getMethod(Method->getSelector(), Method->isInstanceMethod());
+ }
+
+ if (!Method->isOverriding()) {
+ collectOverriddenMethodsFast(TU, Method, overridden);
+ } else {
+ collectOverriddenMethodsSlow(TU, Method, overridden);
+ assert(!overridden.empty() &&
+ "ObjCMethodDecl's overriding bit is not as expected");
+ }
+}
+
std::pair<int, SourceLocation>
cxcursor::getSelectorIdentifierIndexAndLoc(CXCursor cursor) {
if (cursor.kind == CXCursor_ObjCMessageExpr) {
@@ -1134,7 +1198,8 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
= Result.CreateCodeCompletionString(unit->getASTContext(),
unit->getPreprocessor(),
unit->getCodeCompletionTUInfo().getAllocator(),
- unit->getCodeCompletionTUInfo());
+ unit->getCodeCompletionTUInfo(),
+ true);
return String;
}
}
@@ -1147,10 +1212,137 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
= Result.CreateCodeCompletionString(unit->getASTContext(),
unit->getPreprocessor(),
unit->getCodeCompletionTUInfo().getAllocator(),
- unit->getCodeCompletionTUInfo());
+ unit->getCodeCompletionTUInfo(),
+ false);
return String;
}
return NULL;
}
+} // end: extern C.
+
+namespace {
+ struct OverridenCursorsPool {
+ typedef llvm::SmallVector<CXCursor, 2> CursorVec;
+ std::vector<CursorVec*> AllCursors;
+ std::vector<CursorVec*> AvailableCursors;
+
+ ~OverridenCursorsPool() {
+ for (std::vector<CursorVec*>::iterator I = AllCursors.begin(),
+ E = AllCursors.end(); I != E; ++I) {
+ delete *I;
+ }
+ }
+ };
+}
+
+void *cxcursor::createOverridenCXCursorsPool() {
+ return new OverridenCursorsPool();
+}
+
+void cxcursor::disposeOverridenCXCursorsPool(void *pool) {
+ delete static_cast<OverridenCursorsPool*>(pool);
+}
+
+extern "C" {
+void clang_getOverriddenCursors(CXCursor cursor,
+ CXCursor **overridden,
+ unsigned *num_overridden) {
+ if (overridden)
+ *overridden = 0;
+ if (num_overridden)
+ *num_overridden = 0;
+
+ CXTranslationUnit TU = cxcursor::getCursorTU(cursor);
+
+ if (!overridden || !num_overridden || !TU)
+ return;
+
+ if (!clang_isDeclaration(cursor.kind))
+ return;
+
+ OverridenCursorsPool &pool =
+ *static_cast<OverridenCursorsPool*>(TU->OverridenCursorsPool);
+
+ OverridenCursorsPool::CursorVec *Vec = 0;
+ if (!pool.AvailableCursors.empty()) {
+ Vec = pool.AvailableCursors.back();
+ pool.AvailableCursors.pop_back();
+ }
+ else {
+ Vec = new OverridenCursorsPool::CursorVec();
+ pool.AllCursors.push_back(Vec);
+ }
+
+ // Clear out the vector, but don't free the memory contents. This
+ // reduces malloc() traffic.
+ Vec->clear();
+
+ // Use the first entry to contain a back reference to the vector.
+ // This is a complete hack.
+ CXCursor backRefCursor = MakeCXCursorInvalid(CXCursor_InvalidFile, TU);
+ backRefCursor.data[0] = Vec;
+ assert(cxcursor::getCursorTU(backRefCursor) == TU);
+ Vec->push_back(backRefCursor);
+
+ // Get the overriden cursors.
+ cxcursor::getOverriddenCursors(cursor, *Vec);
+
+ // Did we get any overriden cursors? If not, return Vec to the pool
+ // of available cursor vectors.
+ if (Vec->size() == 1) {
+ pool.AvailableCursors.push_back(Vec);
+ return;
+ }
+
+ // Now tell the caller about the overriden cursors.
+ assert(Vec->size() > 1);
+ *overridden = &((*Vec)[1]);
+ *num_overridden = Vec->size() - 1;
+}
+
+void clang_disposeOverriddenCursors(CXCursor *overridden) {
+ if (!overridden)
+ return;
+
+ // Use pointer arithmetic to get back the first faux entry
+ // which has a back-reference to the TU and the vector.
+ --overridden;
+ OverridenCursorsPool::CursorVec *Vec =
+ static_cast<OverridenCursorsPool::CursorVec*>(overridden->data[0]);
+ CXTranslationUnit TU = getCursorTU(*overridden);
+
+ assert(Vec && TU);
+
+ OverridenCursorsPool &pool =
+ *static_cast<OverridenCursorsPool*>(TU->OverridenCursorsPool);
+
+ pool.AvailableCursors.push_back(Vec);
+}
+
+int clang_Cursor_isDynamicCall(CXCursor C) {
+ const Expr *E = 0;
+ if (clang_isExpression(C.kind))
+ E = getCursorExpr(C);
+ if (!E)
+ return 0;
+
+ if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E))
+ return MsgE->getReceiverKind() == ObjCMessageExpr::Instance;
+
+ const MemberExpr *ME = 0;
+ if (isa<MemberExpr>(E))
+ ME = cast<MemberExpr>(E);
+ else if (const CallExpr *CE = dyn_cast<CallExpr>(E))
+ ME = dyn_cast_or_null<MemberExpr>(CE->getCallee());
+
+ if (ME) {
+ if (const CXXMethodDecl *
+ MD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl()))
+ return MD->isVirtual() && !ME->hasQualifier();
+ }
+
+ return 0;
+}
+
} // end: extern "C"
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index 947b0a3..120b881 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -55,7 +55,7 @@ CXCursor MakeCXCursor(clang::Decl *D, CXTranslationUnit TU,
CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent,
CXTranslationUnit TU,
SourceRange RegionOfInterest = SourceRange());
-CXCursor MakeCXCursorInvalid(CXCursorKind K);
+CXCursor MakeCXCursorInvalid(CXCursorKind K, CXTranslationUnit TU = 0);
/// \brief Create an Objective-C superclass reference at the given location.
CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
@@ -206,8 +206,15 @@ ASTUnit *getCursorASTUnit(CXCursor Cursor);
CXTranslationUnit getCursorTU(CXCursor Cursor);
void getOverriddenCursors(CXCursor cursor,
- SmallVectorImpl<CXCursor> &overridden);
+ SmallVectorImpl<CXCursor> &overridden);
+
+/// \brief Create an opaque pool used for fast generation of overriden
+/// CXCursor arrays.
+void *createOverridenCXCursorsPool();
+/// \brief Dispose of the overriden CXCursors pool.
+void disposeOverridenCXCursorsPool(void *pool);
+
/// \brief Returns a index/location pair for a selector identifier if the cursor
/// points to one.
std::pair<int, SourceLocation> getSelectorIdentifierIndexAndLoc(CXCursor);
diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp
index 8284dc9..fa331de 100644
--- a/tools/libclang/CXStoredDiagnostic.cpp
+++ b/tools/libclang/CXStoredDiagnostic.cpp
@@ -66,13 +66,8 @@ CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const {
*Disable = createCXString("-ferror-limit=0");
return createCXString("-ferror-limit=");
}
-
- bool EnabledByDefault;
- if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) &&
- !EnabledByDefault)
- return createCXString("-pedantic");
- return createCXString("");
+ return createCXString("");
}
unsigned CXStoredDiagnostic::getCategory() const {
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index 3ad867c..37789aa 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -20,6 +20,7 @@ struct CXTranslationUnitImpl {
void *TUData;
void *StringPool;
void *Diagnostics;
+ void *OverridenCursorsPool;
};
}
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 850fac1..15f818a 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -94,7 +94,23 @@ static CXTypeKind GetTypeKind(QualType T) {
CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) {
- CXTypeKind TK = GetTypeKind(T);
+ CXTypeKind TK = CXType_Invalid;
+
+ if (TU && !T.isNull()) {
+ ASTContext &Ctx = static_cast<ASTUnit *>(TU->TUData)->getASTContext();
+ if (Ctx.getLangOpts().ObjC1) {
+ QualType UnqualT = T.getUnqualifiedType();
+ if (Ctx.isObjCIdType(UnqualT))
+ TK = CXType_ObjCId;
+ else if (Ctx.isObjCClassType(UnqualT))
+ TK = CXType_ObjCClass;
+ else if (Ctx.isObjCSelType(UnqualT))
+ TK = CXType_ObjCSel;
+ }
+ }
+ if (TK == CXType_Invalid)
+ TK = GetTypeKind(T);
+
CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }};
return CT;
}
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
index 74a8d37..acf8838 100644
--- a/tools/libclang/IndexBody.cpp
+++ b/tools/libclang/IndexBody.cpp
@@ -9,14 +9,14 @@
#include "IndexingContext.h"
-#include "clang/AST/RecursiveASTVisitor.h"
+#include "RecursiveASTVisitor.h"
using namespace clang;
using namespace cxindex;
namespace {
-class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {
+class BodyIndexer : public cxindex::RecursiveASTVisitor<BodyIndexer> {
IndexingContext &IndexCtx;
const NamedDecl *Parent;
const DeclContext *ParentDC;
@@ -90,13 +90,19 @@ public:
return true;
}
- bool VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
- if (ObjCMethodDecl *MD = E->getObjCNumericLiteralMethod())
+ bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(),
+ Parent, ParentDC, E, CXIdxEntityRef_Direct);
+ return true;
+ }
+
+ bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
+ if (ObjCMethodDecl *MD = E->getBoxingMethod())
IndexCtx.handleReference(MD, E->getLocStart(),
Parent, ParentDC, E, CXIdxEntityRef_Implicit);
return true;
}
-
+
bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod())
IndexCtx.handleReference(MD, E->getLocStart(),
diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp
index c257c34..7560398 100644
--- a/tools/libclang/IndexDecl.cpp
+++ b/tools/libclang/IndexDecl.cpp
@@ -154,7 +154,20 @@ public:
IndexCtx.handleObjCImplementation(D);
IndexCtx.indexTUDeclsInObjCContainer();
- IndexCtx.indexDeclContext(D);
+
+ // Index the ivars first to make sure the synthesized ivars are indexed
+ // before indexing the methods that can reference them.
+ for (ObjCImplementationDecl::ivar_iterator
+ IvarI = D->ivar_begin(),
+ IvarE = D->ivar_end(); IvarI != IvarE; ++IvarI) {
+ IndexCtx.indexDecl(*IvarI);
+ }
+ for (DeclContext::decl_iterator
+ I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
+ if (!isa<ObjCIvarDecl>(*I))
+ IndexCtx.indexDecl(*I);
+ }
+
return true;
}
diff --git a/tools/libclang/IndexTypeSourceInfo.cpp b/tools/libclang/IndexTypeSourceInfo.cpp
index b62d521..67a06f2 100644
--- a/tools/libclang/IndexTypeSourceInfo.cpp
+++ b/tools/libclang/IndexTypeSourceInfo.cpp
@@ -9,14 +9,14 @@
#include "IndexingContext.h"
-#include "clang/AST/RecursiveASTVisitor.h"
+#include "RecursiveASTVisitor.h"
using namespace clang;
using namespace cxindex;
namespace {
-class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {
+class TypeIndexer : public cxindex::RecursiveASTVisitor<TypeIndexer> {
IndexingContext &IndexCtx;
const NamedDecl *Parent;
const DeclContext *ParentDC;
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index e660c4d..8fe9c36 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -353,7 +353,8 @@ static void clang_indexSourceFile_Impl(void *UserData) {
CInvok->getDiagnosticOpts().IgnoreWarnings = true;
ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags,
- /*CaptureDiagnostics=*/true);
+ /*CaptureDiagnostics=*/true,
+ /*UserFilesAreVolatile=*/true);
OwningPtr<CXTUOwner> CXTU(new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit)));
// Recover resources if we crash before exiting this method.
@@ -369,7 +370,6 @@ static void clang_indexSourceFile_Impl(void *UserData) {
IndexActionCleanup(IndexAction.get());
bool Persistent = requestedToGetTU;
- StringRef ResourceFilesPath = CXXIdx->getClangResourcesPath();
bool OnlyLocalDecls = false;
bool PrecompilePreamble = false;
bool CacheCodeCompletionResults = false;
@@ -393,11 +393,13 @@ static void clang_indexSourceFile_Impl(void *UserData) {
IndexAction.get(),
Unit,
Persistent,
- ResourceFilesPath,
+ CXXIdx->getClangResourcesPath(),
OnlyLocalDecls,
/*CaptureDiagnostics=*/true,
PrecompilePreamble,
- CacheCodeCompletionResults);
+ CacheCodeCompletionResults,
+ /*IncludeBriefCommentsInCodeCompletion=*/false,
+ /*UserFilesAreVolatile=*/true);
if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics())
printDiagsToStderr(Unit);
diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h
index 6271660..00e1096 100644
--- a/tools/libclang/IndexingContext.h
+++ b/tools/libclang/IndexingContext.h
@@ -542,10 +542,8 @@ namespace llvm {
}
static unsigned getHashValue(clang::cxindex::RefFileOccurence S) {
- llvm::FoldingSetNodeID ID;
- ID.AddPointer(S.File);
- ID.AddPointer(S.Dcl);
- return ID.ComputeHash();
+ typedef std::pair<const clang::FileEntry *, const clang::Decl *> PairTy;
+ return DenseMapInfo<PairTy>::getHashValue(PairTy(S.File, S.Dcl));
}
static bool isEqual(clang::cxindex::RefFileOccurence LHS,
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index 08bf3c6..975d381 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -15,11 +15,12 @@ EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/libclang.exports
LINK_LIBS_IN_SHARED = 1
SHARED_LIBRARY = 1
-LINK_COMPONENTS := support mc
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \
clangSerialization.a \
clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
- clangAST.a clangLex.a clangBasic.a
+ clangAST.a clangLex.a clangTooling.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
@@ -42,7 +43,7 @@ ifeq ($(HOST_OS),Darwin)
endif
# Extra options to override libtool defaults.
- LLVMLibsOptions += -Wl,-dead_strip -Wl,-seg1addr,0xE0000000
+ LLVMLibsOptions += -Wl,-dead_strip
# Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line
DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/')
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
new file mode 100644
index 0000000..7131025
--- /dev/null
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -0,0 +1,2185 @@
+//===--- RecursiveASTVisitor.h - Recursive AST Visitor ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the RecursiveASTVisitor interface, which recursively
+// traverses the entire AST.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LIBCLANG_RECURSIVEASTVISITOR_H
+#define LLVM_CLANG_LIBCLANG_RECURSIVEASTVISITOR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
+
+// The following three macros are used for meta programming. The code
+// using them is responsible for defining macro OPERATOR().
+
+// All unary operators.
+#define UNARYOP_LIST() \
+ OPERATOR(PostInc) OPERATOR(PostDec) \
+ OPERATOR(PreInc) OPERATOR(PreDec) \
+ OPERATOR(AddrOf) OPERATOR(Deref) \
+ OPERATOR(Plus) OPERATOR(Minus) \
+ OPERATOR(Not) OPERATOR(LNot) \
+ OPERATOR(Real) OPERATOR(Imag) \
+ OPERATOR(Extension)
+
+// All binary operators (excluding compound assign operators).
+#define BINOP_LIST() \
+ OPERATOR(PtrMemD) OPERATOR(PtrMemI) \
+ OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) \
+ OPERATOR(Add) OPERATOR(Sub) OPERATOR(Shl) \
+ OPERATOR(Shr) \
+ \
+ OPERATOR(LT) OPERATOR(GT) OPERATOR(LE) \
+ OPERATOR(GE) OPERATOR(EQ) OPERATOR(NE) \
+ OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) \
+ OPERATOR(LAnd) OPERATOR(LOr) \
+ \
+ OPERATOR(Assign) \
+ OPERATOR(Comma)
+
+// All compound assign operators.
+#define CAO_LIST() \
+ OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) \
+ OPERATOR(Shl) OPERATOR(Shr) OPERATOR(And) OPERATOR(Or) OPERATOR(Xor)
+
+namespace clang {
+namespace cxindex {
+
+// A helper macro to implement short-circuiting when recursing. It
+// invokes CALL_EXPR, which must be a method call, on the derived
+// object (s.t. a user of RecursiveASTVisitor can override the method
+// in CALL_EXPR).
+#define TRY_TO(CALL_EXPR) \
+ do { if (!getDerived().CALL_EXPR) return false; } while (0)
+
+/// \brief A class that does preorder depth-first traversal on the
+/// entire Clang AST and visits each node.
+///
+/// This class performs three distinct tasks:
+/// 1. traverse the AST (i.e. go to each node);
+/// 2. at a given node, walk up the class hierarchy, starting from
+/// the node's dynamic type, until the top-most class (e.g. Stmt,
+/// Decl, or Type) is reached.
+/// 3. given a (node, class) combination, where 'class' is some base
+/// class of the dynamic type of 'node', call a user-overridable
+/// function to actually visit the node.
+///
+/// These tasks are done by three groups of methods, respectively:
+/// 1. TraverseDecl(Decl *x) does task #1. It is the entry point
+/// for traversing an AST rooted at x. This method simply
+/// dispatches (i.e. forwards) to TraverseFoo(Foo *x) where Foo
+/// is the dynamic type of *x, which calls WalkUpFromFoo(x) and
+/// then recursively visits the child nodes of x.
+/// TraverseStmt(Stmt *x) and TraverseType(QualType x) work
+/// similarly.
+/// 2. WalkUpFromFoo(Foo *x) does task #2. It does not try to visit
+/// any child node of x. Instead, it first calls WalkUpFromBar(x)
+/// where Bar is the direct parent class of Foo (unless Foo has
+/// no parent), and then calls VisitFoo(x) (see the next list item).
+/// 3. VisitFoo(Foo *x) does task #3.
+///
+/// These three method groups are tiered (Traverse* > WalkUpFrom* >
+/// Visit*). A method (e.g. Traverse*) may call methods from the same
+/// tier (e.g. other Traverse*) or one tier lower (e.g. WalkUpFrom*).
+/// It may not call methods from a higher tier.
+///
+/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar
+/// is Foo's super class) before calling VisitFoo(), the result is
+/// that the Visit*() methods for a given node are called in the
+/// top-down order (e.g. for a node of type NamedDecl, the order will
+/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()).
+///
+/// This scheme guarantees that all Visit*() calls for the same AST
+/// node are grouped together. In other words, Visit*() methods for
+/// different nodes are never interleaved.
+///
+/// Stmts are traversed internally using a data queue to avoid a stack overflow
+/// with hugely nested ASTs.
+///
+/// Clients of this visitor should subclass the visitor (providing
+/// themselves as the template argument, using the curiously recurring
+/// template pattern) and override any of the Traverse*, WalkUpFrom*,
+/// and Visit* methods for declarations, types, statements,
+/// expressions, or other AST nodes where the visitor should customize
+/// behavior. Most users only need to override Visit*. Advanced
+/// users may override Traverse* and WalkUpFrom* to implement custom
+/// traversal strategies. Returning false from one of these overridden
+/// functions will abort the entire traversal.
+///
+/// By default, this visitor tries to visit every part of the explicit
+/// source code exactly once. The default policy towards templates
+/// is to descend into the 'pattern' class or function body, not any
+/// explicit or implicit instantiations. Explicit specializations
+/// are still visited, and the patterns of partial specializations
+/// are visited separately. This behavior can be changed by
+/// overriding shouldVisitTemplateInstantiations() in the derived class
+/// to return true, in which case all known implicit and explicit
+/// instantiations will be visited at the same time as the pattern
+/// from which they were produced.
+template<typename Derived>
+class RecursiveASTVisitor {
+public:
+ /// \brief Return a reference to the derived class.
+ Derived &getDerived() { return *static_cast<Derived*>(this); }
+
+ /// \brief Return whether this visitor should recurse into
+ /// template instantiations.
+ bool shouldVisitTemplateInstantiations() const { return false; }
+
+ /// \brief Return whether this visitor should recurse into the types of
+ /// TypeLocs.
+ bool shouldWalkTypesOfTypeLocs() const { return true; }
+
+ /// \brief Recursively visit a statement or expression, by
+ /// dispatching to Traverse*() based on the argument's dynamic type.
+ ///
+ /// \returns false if the visitation was terminated early, true
+ /// otherwise (including when the argument is NULL).
+ bool TraverseStmt(Stmt *S);
+
+ /// \brief Recursively visit a type, by dispatching to
+ /// Traverse*Type() based on the argument's getTypeClass() property.
+ ///
+ /// \returns false if the visitation was terminated early, true
+ /// otherwise (including when the argument is a Null type).
+ bool TraverseType(QualType T);
+
+ /// \brief Recursively visit a type with location, by dispatching to
+ /// Traverse*TypeLoc() based on the argument type's getTypeClass() property.
+ ///
+ /// \returns false if the visitation was terminated early, true
+ /// otherwise (including when the argument is a Null type location).
+ bool TraverseTypeLoc(TypeLoc TL);
+
+ /// \brief Recursively visit a declaration, by dispatching to
+ /// Traverse*Decl() based on the argument's dynamic type.
+ ///
+ /// \returns false if the visitation was terminated early, true
+ /// otherwise (including when the argument is NULL).
+ bool TraverseDecl(Decl *D);
+
+ /// \brief Recursively visit a C++ nested-name-specifier.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
+
+ /// \brief Recursively visit a C++ nested-name-specifier with location
+ /// information.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
+
+ /// \brief Recursively visit a name with its location information.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo);
+
+ /// \brief Recursively visit a template name and dispatch to the
+ /// appropriate method.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseTemplateName(TemplateName Template);
+
+ /// \brief Recursively visit a template argument and dispatch to the
+ /// appropriate method for the argument type.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ // FIXME: migrate callers to TemplateArgumentLoc instead.
+ bool TraverseTemplateArgument(const TemplateArgument &Arg);
+
+ /// \brief Recursively visit a template argument location and dispatch to the
+ /// appropriate method for the argument type.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc);
+
+ /// \brief Recursively visit a set of template arguments.
+ /// This can be overridden by a subclass, but it's not expected that
+ /// will be needed -- this visitor always dispatches to another.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead.
+ bool TraverseTemplateArguments(const TemplateArgument *Args,
+ unsigned NumArgs);
+
+ /// \brief Recursively visit a constructor initializer. This
+ /// automatically dispatches to another visitor for the initializer
+ /// expression, but not for the name of the initializer, so may
+ /// be overridden for clients that need access to the name.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init);
+
+ /// \brief Recursively visit a lambda capture.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseLambdaCapture(LambdaExpr::Capture C);
+
+ // ---- Methods on Stmts ----
+
+ // Declare Traverse*() for all concrete Stmt classes.
+#define ABSTRACT_STMT(STMT)
+#define STMT(CLASS, PARENT) \
+ bool Traverse##CLASS(CLASS *S);
+#include "clang/AST/StmtNodes.inc"
+ // The above header #undefs ABSTRACT_STMT and STMT upon exit.
+
+ // Define WalkUpFrom*() and empty Visit*() for all Stmt classes.
+ bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitStmt(S); }
+ bool VisitStmt(Stmt *S) { return true; }
+#define STMT(CLASS, PARENT) \
+ bool WalkUpFrom##CLASS(CLASS *S) { \
+ TRY_TO(WalkUpFrom##PARENT(S)); \
+ TRY_TO(Visit##CLASS(S)); \
+ return true; \
+ } \
+ bool Visit##CLASS(CLASS *S) { return true; }
+#include "clang/AST/StmtNodes.inc"
+
+ // Define Traverse*(), WalkUpFrom*(), and Visit*() for unary
+ // operator methods. Unary operators are not classes in themselves
+ // (they're all opcodes in UnaryOperator) but do have visitors.
+#define OPERATOR(NAME) \
+ bool TraverseUnary##NAME(UnaryOperator *S) { \
+ TRY_TO(WalkUpFromUnary##NAME(S)); \
+ StmtQueueAction StmtQueue(*this); \
+ StmtQueue.queue(S->getSubExpr()); \
+ return true; \
+ } \
+ bool WalkUpFromUnary##NAME(UnaryOperator *S) { \
+ TRY_TO(WalkUpFromUnaryOperator(S)); \
+ TRY_TO(VisitUnary##NAME(S)); \
+ return true; \
+ } \
+ bool VisitUnary##NAME(UnaryOperator *S) { return true; }
+
+ UNARYOP_LIST()
+#undef OPERATOR
+
+ // Define Traverse*(), WalkUpFrom*(), and Visit*() for binary
+ // operator methods. Binary operators are not classes in themselves
+ // (they're all opcodes in BinaryOperator) but do have visitors.
+#define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE) \
+ bool TraverseBin##NAME(BINOP_TYPE *S) { \
+ TRY_TO(WalkUpFromBin##NAME(S)); \
+ StmtQueueAction StmtQueue(*this); \
+ StmtQueue.queue(S->getLHS()); \
+ StmtQueue.queue(S->getRHS()); \
+ return true; \
+ } \
+ bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \
+ TRY_TO(WalkUpFrom##BINOP_TYPE(S)); \
+ TRY_TO(VisitBin##NAME(S)); \
+ return true; \
+ } \
+ bool VisitBin##NAME(BINOP_TYPE *S) { return true; }
+
+#define OPERATOR(NAME) GENERAL_BINOP_FALLBACK(NAME, BinaryOperator)
+ BINOP_LIST()
+#undef OPERATOR
+
+ // Define Traverse*(), WalkUpFrom*(), and Visit*() for compound
+ // assignment methods. Compound assignment operators are not
+ // classes in themselves (they're all opcodes in
+ // CompoundAssignOperator) but do have visitors.
+#define OPERATOR(NAME) \
+ GENERAL_BINOP_FALLBACK(NAME##Assign, CompoundAssignOperator)
+
+ CAO_LIST()
+#undef OPERATOR
+#undef GENERAL_BINOP_FALLBACK
+
+ // ---- Methods on Types ----
+ // FIXME: revamp to take TypeLoc's rather than Types.
+
+ // Declare Traverse*() for all concrete Type classes.
+#define ABSTRACT_TYPE(CLASS, BASE)
+#define TYPE(CLASS, BASE) \
+ bool Traverse##CLASS##Type(CLASS##Type *T);
+#include "clang/AST/TypeNodes.def"
+ // The above header #undefs ABSTRACT_TYPE and TYPE upon exit.
+
+ // Define WalkUpFrom*() and empty Visit*() for all Type classes.
+ bool WalkUpFromType(Type *T) { return getDerived().VisitType(T); }
+ bool VisitType(Type *T) { return true; }
+#define TYPE(CLASS, BASE) \
+ bool WalkUpFrom##CLASS##Type(CLASS##Type *T) { \
+ TRY_TO(WalkUpFrom##BASE(T)); \
+ TRY_TO(Visit##CLASS##Type(T)); \
+ return true; \
+ } \
+ bool Visit##CLASS##Type(CLASS##Type *T) { return true; }
+#include "clang/AST/TypeNodes.def"
+
+ // ---- Methods on TypeLocs ----
+ // FIXME: this currently just calls the matching Type methods
+
+ // Declare Traverse*() for all concrete Type classes.
+#define ABSTRACT_TYPELOC(CLASS, BASE)
+#define TYPELOC(CLASS, BASE) \
+ bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
+#include "clang/AST/TypeLocNodes.def"
+ // The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit.
+
+ // Define WalkUpFrom*() and empty Visit*() for all TypeLoc classes.
+ bool WalkUpFromTypeLoc(TypeLoc TL) { return getDerived().VisitTypeLoc(TL); }
+ bool VisitTypeLoc(TypeLoc TL) { return true; }
+
+ // QualifiedTypeLoc and UnqualTypeLoc are not declared in
+ // TypeNodes.def and thus need to be handled specially.
+ bool WalkUpFromQualifiedTypeLoc(QualifiedTypeLoc TL) {
+ return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc());
+ }
+ bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { return true; }
+ bool WalkUpFromUnqualTypeLoc(UnqualTypeLoc TL) {
+ return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc());
+ }
+ bool VisitUnqualTypeLoc(UnqualTypeLoc TL) { return true; }
+
+ // Note that BASE includes trailing 'Type' which CLASS doesn't.
+#define TYPE(CLASS, BASE) \
+ bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
+ TRY_TO(WalkUpFrom##BASE##Loc(TL)); \
+ TRY_TO(Visit##CLASS##TypeLoc(TL)); \
+ return true; \
+ } \
+ bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; }
+#include "clang/AST/TypeNodes.def"
+
+ // ---- Methods on Decls ----
+
+ // Declare Traverse*() for all concrete Decl classes.
+#define ABSTRACT_DECL(DECL)
+#define DECL(CLASS, BASE) \
+ bool Traverse##CLASS##Decl(CLASS##Decl *D);
+#include "clang/AST/DeclNodes.inc"
+ // The above header #undefs ABSTRACT_DECL and DECL upon exit.
+
+ // Define WalkUpFrom*() and empty Visit*() for all Decl classes.
+ bool WalkUpFromDecl(Decl *D) { return getDerived().VisitDecl(D); }
+ bool VisitDecl(Decl *D) { return true; }
+#define DECL(CLASS, BASE) \
+ bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D) { \
+ TRY_TO(WalkUpFrom##BASE(D)); \
+ TRY_TO(Visit##CLASS##Decl(D)); \
+ return true; \
+ } \
+ bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; }
+#include "clang/AST/DeclNodes.inc"
+
+private:
+ // These are helper methods used by more than one Traverse* method.
+ bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
+ bool TraverseClassInstantiations(ClassTemplateDecl *D);
+ bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
+ bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
+ unsigned Count);
+ bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
+ bool TraverseRecordHelper(RecordDecl *D);
+ bool TraverseCXXRecordHelper(CXXRecordDecl *D);
+ bool TraverseDeclaratorHelper(DeclaratorDecl *D);
+ bool TraverseDeclContextHelper(DeclContext *DC);
+ bool TraverseFunctionHelper(FunctionDecl *D);
+ bool TraverseVarHelper(VarDecl *D);
+
+ typedef SmallVector<Stmt *, 16> StmtsTy;
+ typedef SmallVector<StmtsTy *, 4> QueuesTy;
+
+ QueuesTy Queues;
+
+ class NewQueueRAII {
+ RecursiveASTVisitor &RAV;
+ public:
+ NewQueueRAII(StmtsTy &queue, RecursiveASTVisitor &RAV) : RAV(RAV) {
+ RAV.Queues.push_back(&queue);
+ }
+ ~NewQueueRAII() {
+ RAV.Queues.pop_back();
+ }
+ };
+
+ StmtsTy &getCurrentQueue() {
+ assert(!Queues.empty() && "base TraverseStmt was never called?");
+ return *Queues.back();
+ }
+
+public:
+ class StmtQueueAction {
+ StmtsTy &CurrQueue;
+ public:
+ explicit StmtQueueAction(RecursiveASTVisitor &RAV)
+ : CurrQueue(RAV.getCurrentQueue()) { }
+
+ void queue(Stmt *S) {
+ CurrQueue.push_back(S);
+ }
+ };
+};
+
+#define DISPATCH(NAME, CLASS, VAR) \
+ return getDerived().Traverse##NAME(static_cast<CLASS*>(VAR))
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
+ if (!S)
+ return true;
+
+ StmtsTy Queue, StmtsToEnqueu;
+ Queue.push_back(S);
+ NewQueueRAII NQ(StmtsToEnqueu, *this);
+
+ while (!Queue.empty()) {
+ S = Queue.pop_back_val();
+ if (!S)
+ continue;
+
+ StmtsToEnqueu.clear();
+
+#define DISPATCH_STMT(NAME, CLASS, VAR) \
+ TRY_TO(Traverse##NAME(static_cast<CLASS*>(VAR))); break
+
+ // If we have a binary expr, dispatch to the subcode of the binop. A smart
+ // optimizer (e.g. LLVM) will fold this comparison into the switch stmt
+ // below.
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
+ switch (BinOp->getOpcode()) {
+#define OPERATOR(NAME) \
+ case BO_##NAME: DISPATCH_STMT(Bin##NAME, BinaryOperator, S);
+
+ BINOP_LIST()
+#undef OPERATOR
+#undef BINOP_LIST
+
+#define OPERATOR(NAME) \
+ case BO_##NAME##Assign: \
+ DISPATCH_STMT(Bin##NAME##Assign, CompoundAssignOperator, S);
+
+ CAO_LIST()
+#undef OPERATOR
+#undef CAO_LIST
+ }
+ } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
+ switch (UnOp->getOpcode()) {
+#define OPERATOR(NAME) \
+ case UO_##NAME: DISPATCH_STMT(Unary##NAME, UnaryOperator, S);
+
+ UNARYOP_LIST()
+#undef OPERATOR
+#undef UNARYOP_LIST
+ }
+ } else {
+
+ // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
+ switch (S->getStmtClass()) {
+ case Stmt::NoStmtClass: break;
+#define ABSTRACT_STMT(STMT)
+#define STMT(CLASS, PARENT) \
+ case Stmt::CLASS##Class: DISPATCH_STMT(CLASS, CLASS, S);
+#include "clang/AST/StmtNodes.inc"
+ }
+ }
+
+ for (SmallVector<Stmt *, 8>::reverse_iterator
+ RI = StmtsToEnqueu.rbegin(),
+ RE = StmtsToEnqueu.rend(); RI != RE; ++RI)
+ Queue.push_back(*RI);
+ }
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
+ if (T.isNull())
+ return true;
+
+ switch (T->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, BASE)
+#define TYPE(CLASS, BASE) \
+ case Type::CLASS: DISPATCH(CLASS##Type, CLASS##Type, \
+ const_cast<Type*>(T.getTypePtr()));
+#include "clang/AST/TypeNodes.def"
+ }
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
+ if (TL.isNull())
+ return true;
+
+ switch (TL.getTypeLocClass()) {
+#define ABSTRACT_TYPELOC(CLASS, BASE)
+#define TYPELOC(CLASS, BASE) \
+ case TypeLoc::CLASS: \
+ return getDerived().Traverse##CLASS##TypeLoc(*cast<CLASS##TypeLoc>(&TL));
+#include "clang/AST/TypeLocNodes.def"
+ }
+
+ return true;
+}
+
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
+ if (!D)
+ return true;
+
+ // As a syntax visitor, we want to ignore declarations for
+ // implicitly-defined declarations (ones not typed explicitly by the
+ // user).
+ if (D->isImplicit())
+ return true;
+
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(DECL)
+#define DECL(CLASS, BASE) \
+ case Decl::CLASS: DISPATCH(CLASS##Decl, CLASS##Decl, D);
+#include "clang/AST/DeclNodes.inc"
+ }
+
+ return true;
+}
+
+#undef DISPATCH
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
+ NestedNameSpecifier *NNS) {
+ if (!NNS)
+ return true;
+
+ if (NNS->getPrefix())
+ TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix()));
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ case NestedNameSpecifier::Global:
+ return true;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ TRY_TO(TraverseType(QualType(NNS->getAsType(), 0)));
+ }
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
+ NestedNameSpecifierLoc NNS) {
+ if (!NNS)
+ return true;
+
+ if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
+ TRY_TO(TraverseNestedNameSpecifierLoc(Prefix));
+
+ switch (NNS.getNestedNameSpecifier()->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ case NestedNameSpecifier::Global:
+ return true;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ TRY_TO(TraverseTypeLoc(NNS.getTypeLoc()));
+ break;
+ }
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
+ DeclarationNameInfo NameInfo) {
+ switch (NameInfo.getName().getNameKind()) {
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo())
+ TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
+
+ break;
+
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXLiteralOperatorName:
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) {
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
+ TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier()));
+ else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier()));
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
+ const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ return true;
+
+ case TemplateArgument::Type:
+ return getDerived().TraverseType(Arg.getAsType());
+
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ return getDerived().TraverseTemplateName(
+ Arg.getAsTemplateOrTemplatePattern());
+
+ case TemplateArgument::Expression:
+ return getDerived().TraverseStmt(Arg.getAsExpr());
+
+ case TemplateArgument::Pack:
+ return getDerived().TraverseTemplateArguments(Arg.pack_begin(),
+ Arg.pack_size());
+ }
+
+ return true;
+}
+
+// FIXME: no template name location?
+// FIXME: no source locations for a template argument pack?
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
+ const TemplateArgumentLoc &ArgLoc) {
+ const TemplateArgument &Arg = ArgLoc.getArgument();
+
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ return true;
+
+ case TemplateArgument::Type: {
+ // FIXME: how can TSI ever be NULL?
+ if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo())
+ return getDerived().TraverseTypeLoc(TSI->getTypeLoc());
+ else
+ return getDerived().TraverseType(Arg.getAsType());
+ }
+
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ if (ArgLoc.getTemplateQualifierLoc())
+ TRY_TO(getDerived().TraverseNestedNameSpecifierLoc(
+ ArgLoc.getTemplateQualifierLoc()));
+ return getDerived().TraverseTemplateName(
+ Arg.getAsTemplateOrTemplatePattern());
+
+ case TemplateArgument::Expression:
+ return getDerived().TraverseStmt(ArgLoc.getSourceExpression());
+
+ case TemplateArgument::Pack:
+ return getDerived().TraverseTemplateArguments(Arg.pack_begin(),
+ Arg.pack_size());
+ }
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments(
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ TRY_TO(TraverseTemplateArgument(Args[I]));
+ }
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
+ CXXCtorInitializer *Init) {
+ if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo())
+ TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
+
+ if (Init->isWritten())
+ TRY_TO(TraverseStmt(Init->getInit()));
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){
+ return true;
+}
+
+// ----------------- Type traversal -----------------
+
+// This macro makes available a variable T, the passed-in type.
+#define DEF_TRAVERSE_TYPE(TYPE, CODE) \
+ template<typename Derived> \
+ bool RecursiveASTVisitor<Derived>::Traverse##TYPE (TYPE *T) { \
+ TRY_TO(WalkUpFrom##TYPE (T)); \
+ { CODE; } \
+ return true; \
+ }
+
+DEF_TRAVERSE_TYPE(BuiltinType, { })
+
+DEF_TRAVERSE_TYPE(ComplexType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
+
+DEF_TRAVERSE_TYPE(PointerType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
+
+DEF_TRAVERSE_TYPE(BlockPointerType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
+
+DEF_TRAVERSE_TYPE(LValueReferenceType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
+
+DEF_TRAVERSE_TYPE(RValueReferenceType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
+
+DEF_TRAVERSE_TYPE(MemberPointerType, {
+ TRY_TO(TraverseType(QualType(T->getClass(), 0)));
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
+
+DEF_TRAVERSE_TYPE(ConstantArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
+
+DEF_TRAVERSE_TYPE(IncompleteArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
+
+DEF_TRAVERSE_TYPE(VariableArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ TRY_TO(TraverseStmt(T->getSizeExpr()));
+ })
+
+DEF_TRAVERSE_TYPE(DependentSizedArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ if (T->getSizeExpr())
+ TRY_TO(TraverseStmt(T->getSizeExpr()));
+ })
+
+DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, {
+ if (T->getSizeExpr())
+ TRY_TO(TraverseStmt(T->getSizeExpr()));
+ TRY_TO(TraverseType(T->getElementType()));
+ })
+
+DEF_TRAVERSE_TYPE(VectorType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
+
+DEF_TRAVERSE_TYPE(ExtVectorType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
+
+DEF_TRAVERSE_TYPE(FunctionNoProtoType, {
+ TRY_TO(TraverseType(T->getResultType()));
+ })
+
+DEF_TRAVERSE_TYPE(FunctionProtoType, {
+ TRY_TO(TraverseType(T->getResultType()));
+
+ for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
+ AEnd = T->arg_type_end();
+ A != AEnd; ++A) {
+ TRY_TO(TraverseType(*A));
+ }
+
+ for (FunctionProtoType::exception_iterator E = T->exception_begin(),
+ EEnd = T->exception_end();
+ E != EEnd; ++E) {
+ TRY_TO(TraverseType(*E));
+ }
+ })
+
+DEF_TRAVERSE_TYPE(UnresolvedUsingType, { })
+DEF_TRAVERSE_TYPE(TypedefType, { })
+
+DEF_TRAVERSE_TYPE(TypeOfExprType, {
+ TRY_TO(TraverseStmt(T->getUnderlyingExpr()));
+ })
+
+DEF_TRAVERSE_TYPE(TypeOfType, {
+ TRY_TO(TraverseType(T->getUnderlyingType()));
+ })
+
+DEF_TRAVERSE_TYPE(DecltypeType, {
+ TRY_TO(TraverseStmt(T->getUnderlyingExpr()));
+ })
+
+DEF_TRAVERSE_TYPE(UnaryTransformType, {
+ TRY_TO(TraverseType(T->getBaseType()));
+ TRY_TO(TraverseType(T->getUnderlyingType()));
+ })
+
+DEF_TRAVERSE_TYPE(AutoType, {
+ TRY_TO(TraverseType(T->getDeducedType()));
+ })
+
+DEF_TRAVERSE_TYPE(RecordType, { })
+DEF_TRAVERSE_TYPE(EnumType, { })
+DEF_TRAVERSE_TYPE(TemplateTypeParmType, { })
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { })
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { })
+
+DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
+ TRY_TO(TraverseTemplateName(T->getTemplateName()));
+ TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
+ })
+
+DEF_TRAVERSE_TYPE(InjectedClassNameType, { })
+
+DEF_TRAVERSE_TYPE(AttributedType, {
+ TRY_TO(TraverseType(T->getModifiedType()));
+ })
+
+DEF_TRAVERSE_TYPE(ParenType, {
+ TRY_TO(TraverseType(T->getInnerType()));
+ })
+
+DEF_TRAVERSE_TYPE(ElaboratedType, {
+ if (T->getQualifier()) {
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+ }
+ TRY_TO(TraverseType(T->getNamedType()));
+ })
+
+DEF_TRAVERSE_TYPE(DependentNameType, {
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+ })
+
+DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, {
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+ TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
+ })
+
+DEF_TRAVERSE_TYPE(PackExpansionType, {
+ TRY_TO(TraverseType(T->getPattern()));
+ })
+
+DEF_TRAVERSE_TYPE(ObjCInterfaceType, { })
+
+DEF_TRAVERSE_TYPE(ObjCObjectType, {
+ // We have to watch out here because an ObjCInterfaceType's base
+ // type is itself.
+ if (T->getBaseType().getTypePtr() != T)
+ TRY_TO(TraverseType(T->getBaseType()));
+ })
+
+DEF_TRAVERSE_TYPE(ObjCObjectPointerType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
+
+DEF_TRAVERSE_TYPE(AtomicType, {
+ TRY_TO(TraverseType(T->getValueType()));
+ })
+
+#undef DEF_TRAVERSE_TYPE
+
+// ----------------- TypeLoc traversal -----------------
+
+// This macro makes available a variable TL, the passed-in TypeLoc.
+// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc,
+// in addition to WalkUpFrom* for the TypeLoc itself, such that existing
+// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods
+// continue to work.
+#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \
+ template<typename Derived> \
+ bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \
+ if (getDerived().shouldWalkTypesOfTypeLocs()) \
+ TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE*>(TL.getTypePtr()))); \
+ TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \
+ { CODE; } \
+ return true; \
+ }
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc(
+ QualifiedTypeLoc TL) {
+ // Move this over to the 'main' typeloc tree. Note that this is a
+ // move -- we pretend that we were really looking at the unqualified
+ // typeloc all along -- rather than a recursion, so we don't follow
+ // the normal CRTP plan of going through
+ // getDerived().TraverseTypeLoc. If we did, we'd be traversing
+ // twice for the same type (once as a QualifiedTypeLoc version of
+ // the type, once as an UnqualifiedTypeLoc version of the type),
+ // which in effect means we'd call VisitTypeLoc twice with the
+ // 'same' type. This solves that problem, at the cost of never
+ // seeing the qualified version of the type (unless the client
+ // subclasses TraverseQualifiedTypeLoc themselves). It's not a
+ // perfect solution. A perfect solution probably requires making
+ // QualifiedTypeLoc a wrapper around TypeLoc -- like QualType is a
+ // wrapper around Type* -- rather than being its own class in the
+ // type hierarchy.
+ return TraverseTypeLoc(TL.getUnqualifiedLoc());
+}
+
+DEF_TRAVERSE_TYPELOC(BuiltinType, { })
+
+// FIXME: ComplexTypeLoc is unfinished
+DEF_TRAVERSE_TYPELOC(ComplexType, {
+ TRY_TO(TraverseType(TL.getTypePtr()->getElementType()));
+ })
+
+DEF_TRAVERSE_TYPELOC(PointerType, {
+ TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(BlockPointerType, {
+ TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(LValueReferenceType, {
+ TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(RValueReferenceType, {
+ TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
+ })
+
+// FIXME: location of base class?
+// We traverse this in the type case as well, but how is it not reached through
+// the pointee type?
+DEF_TRAVERSE_TYPELOC(MemberPointerType, {
+ TRY_TO(TraverseType(QualType(TL.getTypePtr()->getClass(), 0)));
+ TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
+ })
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
+ // This isn't available for ArrayType, but is for the ArrayTypeLoc.
+ TRY_TO(TraverseStmt(TL.getSizeExpr()));
+ return true;
+}
+
+DEF_TRAVERSE_TYPELOC(ConstantArrayType, {
+ TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
+ return TraverseArrayTypeLocHelper(TL);
+ })
+
+DEF_TRAVERSE_TYPELOC(IncompleteArrayType, {
+ TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
+ return TraverseArrayTypeLocHelper(TL);
+ })
+
+DEF_TRAVERSE_TYPELOC(VariableArrayType, {
+ TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
+ return TraverseArrayTypeLocHelper(TL);
+ })
+
+DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, {
+ TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
+ return TraverseArrayTypeLocHelper(TL);
+ })
+
+// FIXME: order? why not size expr first?
+// FIXME: base VectorTypeLoc is unfinished
+DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, {
+ if (TL.getTypePtr()->getSizeExpr())
+ TRY_TO(TraverseStmt(TL.getTypePtr()->getSizeExpr()));
+ TRY_TO(TraverseType(TL.getTypePtr()->getElementType()));
+ })
+
+// FIXME: VectorTypeLoc is unfinished
+DEF_TRAVERSE_TYPELOC(VectorType, {
+ TRY_TO(TraverseType(TL.getTypePtr()->getElementType()));
+ })
+
+// FIXME: size and attributes
+// FIXME: base VectorTypeLoc is unfinished
+DEF_TRAVERSE_TYPELOC(ExtVectorType, {
+ TRY_TO(TraverseType(TL.getTypePtr()->getElementType()));
+ })
+
+DEF_TRAVERSE_TYPELOC(FunctionNoProtoType, {
+ TRY_TO(TraverseTypeLoc(TL.getResultLoc()));
+ })
+
+// FIXME: location of exception specifications (attributes?)
+DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
+ TRY_TO(TraverseTypeLoc(TL.getResultLoc()));
+
+ const FunctionProtoType *T = TL.getTypePtr();
+
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
+ if (TL.getArg(I)) {
+ TRY_TO(TraverseDecl(TL.getArg(I)));
+ } else if (I < T->getNumArgs()) {
+ TRY_TO(TraverseType(T->getArgType(I)));
+ }
+ }
+
+ for (FunctionProtoType::exception_iterator E = T->exception_begin(),
+ EEnd = T->exception_end();
+ E != EEnd; ++E) {
+ TRY_TO(TraverseType(*E));
+ }
+ })
+
+DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, { })
+DEF_TRAVERSE_TYPELOC(TypedefType, { })
+
+DEF_TRAVERSE_TYPELOC(TypeOfExprType, {
+ TRY_TO(TraverseStmt(TL.getUnderlyingExpr()));
+ })
+
+DEF_TRAVERSE_TYPELOC(TypeOfType, {
+ TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
+ })
+
+// FIXME: location of underlying expr
+DEF_TRAVERSE_TYPELOC(DecltypeType, {
+ TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
+ })
+
+DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
+ TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(AutoType, {
+ TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
+ })
+
+DEF_TRAVERSE_TYPELOC(RecordType, { })
+DEF_TRAVERSE_TYPELOC(EnumType, { })
+DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, { })
+DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { })
+DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { })
+
+// FIXME: use the loc for the template name?
+DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
+ TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
+ TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
+ }
+ })
+
+DEF_TRAVERSE_TYPELOC(InjectedClassNameType, { })
+
+DEF_TRAVERSE_TYPELOC(ParenType, {
+ TRY_TO(TraverseTypeLoc(TL.getInnerLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(AttributedType, {
+ TRY_TO(TraverseTypeLoc(TL.getModifiedLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(ElaboratedType, {
+ if (TL.getQualifierLoc()) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
+ }
+ TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(DependentNameType, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
+ if (TL.getQualifierLoc()) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
+ }
+
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
+ TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
+ }
+ })
+
+DEF_TRAVERSE_TYPELOC(PackExpansionType, {
+ TRY_TO(TraverseTypeLoc(TL.getPatternLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, { })
+
+DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
+ // We have to watch out here because an ObjCInterfaceType's base
+ // type is itself.
+ if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr())
+ TRY_TO(TraverseTypeLoc(TL.getBaseLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, {
+ TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
+ })
+
+DEF_TRAVERSE_TYPELOC(AtomicType, {
+ TRY_TO(TraverseTypeLoc(TL.getValueLoc()));
+ })
+
+#undef DEF_TRAVERSE_TYPELOC
+
+// ----------------- Decl traversal -----------------
+//
+// For a Decl, we automate (in the DEF_TRAVERSE_DECL macro) traversing
+// the children that come from the DeclContext associated with it.
+// Therefore each Traverse* only needs to worry about children other
+// than those.
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) {
+ if (!DC)
+ return true;
+
+ for (DeclContext::decl_iterator Child = DC->decls_begin(),
+ ChildEnd = DC->decls_end();
+ Child != ChildEnd; ++Child) {
+ // BlockDecls are traversed through BlockExprs.
+ if (!isa<BlockDecl>(*Child))
+ TRY_TO(TraverseDecl(*Child));
+ }
+
+ return true;
+}
+
+// This macro makes available a variable D, the passed-in decl.
+#define DEF_TRAVERSE_DECL(DECL, CODE) \
+template<typename Derived> \
+bool RecursiveASTVisitor<Derived>::Traverse##DECL (DECL *D) { \
+ TRY_TO(WalkUpFrom##DECL (D)); \
+ { CODE; } \
+ TRY_TO(TraverseDeclContextHelper(dyn_cast<DeclContext>(D))); \
+ return true; \
+}
+
+DEF_TRAVERSE_DECL(AccessSpecDecl, { })
+
+DEF_TRAVERSE_DECL(BlockDecl, {
+ if (TypeSourceInfo *TInfo = D->getSignatureAsWritten())
+ TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
+ TRY_TO(TraverseStmt(D->getBody()));
+ // This return statement makes sure the traversal of nodes in
+ // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
+ // is skipped - don't remove it.
+ return true;
+ })
+
+DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
+ TRY_TO(TraverseStmt(D->getAsmString()));
+ })
+
+DEF_TRAVERSE_DECL(ImportDecl, { })
+
+DEF_TRAVERSE_DECL(FriendDecl, {
+ // Friend is either decl or a type.
+ if (D->getFriendType())
+ TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
+ else
+ TRY_TO(TraverseDecl(D->getFriendDecl()));
+ })
+
+DEF_TRAVERSE_DECL(FriendTemplateDecl, {
+ if (D->getFriendType())
+ TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
+ else
+ TRY_TO(TraverseDecl(D->getFriendDecl()));
+ for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) {
+ TemplateParameterList *TPL = D->getTemplateParameterList(I);
+ for (TemplateParameterList::iterator ITPL = TPL->begin(),
+ ETPL = TPL->end();
+ ITPL != ETPL; ++ITPL) {
+ TRY_TO(TraverseDecl(*ITPL));
+ }
+ }
+ })
+
+DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
+ TRY_TO(TraverseDecl(D->getSpecialization()));
+ })
+
+DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
+
+DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {
+ // FIXME: implement this
+ })
+
+DEF_TRAVERSE_DECL(StaticAssertDecl, {
+ TRY_TO(TraverseStmt(D->getAssertExpr()));
+ TRY_TO(TraverseStmt(D->getMessage()));
+ })
+
+DEF_TRAVERSE_DECL(TranslationUnitDecl, {
+ // Code in an unnamed namespace shows up automatically in
+ // decls_begin()/decls_end(). Thus we don't need to recurse on
+ // D->getAnonymousNamespace().
+ })
+
+DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
+ // We shouldn't traverse an aliased namespace, since it will be
+ // defined (and, therefore, traversed) somewhere else.
+ //
+ // This return statement makes sure the traversal of nodes in
+ // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
+ // is skipped - don't remove it.
+ return true;
+ })
+
+DEF_TRAVERSE_DECL(LabelDecl, {
+ // There is no code in a LabelDecl.
+})
+
+
+DEF_TRAVERSE_DECL(NamespaceDecl, {
+ // Code in an unnamed namespace shows up automatically in
+ // decls_begin()/decls_end(). Thus we don't need to recurse on
+ // D->getAnonymousNamespace().
+ })
+
+DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCCategoryDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCImplementationDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCProtocolDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCMethodDecl, {
+ if (D->getResultTypeSourceInfo()) {
+ TRY_TO(TraverseTypeLoc(D->getResultTypeSourceInfo()->getTypeLoc()));
+ }
+ for (ObjCMethodDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ if (D->isThisDeclarationADefinition()) {
+ TRY_TO(TraverseStmt(D->getBody()));
+ }
+ return true;
+ })
+
+DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(UsingDecl, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
+ })
+
+DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ })
+
+DEF_TRAVERSE_DECL(UsingShadowDecl, { })
+
+// A helper method for TemplateDecl's children.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
+ TemplateParameterList *TPL) {
+ if (TPL) {
+ for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
+ I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ }
+ return true;
+}
+
+// A helper method for traversing the implicit instantiations of a
+// class template.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
+ ClassTemplateDecl *D) {
+ ClassTemplateDecl::spec_iterator end = D->spec_end();
+ for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
+ ClassTemplateSpecializationDecl* SD = *it;
+
+ switch (SD->getSpecializationKind()) {
+ // Visit the implicit instantiations with the requested pattern.
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ TRY_TO(TraverseDecl(SD));
+ break;
+
+ // We don't need to do anything on an explicit instantiation
+ // or explicit specialization because there will be an explicit
+ // node for it elsewhere.
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ case TSK_ExplicitSpecialization:
+ break;
+ }
+ }
+
+ return true;
+}
+
+DEF_TRAVERSE_DECL(ClassTemplateDecl, {
+ CXXRecordDecl* TempDecl = D->getTemplatedDecl();
+ TRY_TO(TraverseDecl(TempDecl));
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+
+ // By default, we do not traverse the instantiations of
+ // class templates since they do not appear in the user code. The
+ // following code optionally traverses them.
+ //
+ // We only traverse the class instantiations when we see the canonical
+ // declaration of the template, to ensure we only visit them once.
+ if (getDerived().shouldVisitTemplateInstantiations() &&
+ D == D->getCanonicalDecl())
+ TRY_TO(TraverseClassInstantiations(D));
+
+ // Note that getInstantiatedFromMemberTemplate() is just a link
+ // from a template instantiation back to the template from which
+ // it was instantiated, and thus should not be traversed.
+ })
+
+// A helper method for traversing the instantiations of a
+// function while skipping its specializations.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
+ FunctionTemplateDecl *D) {
+ FunctionTemplateDecl::spec_iterator end = D->spec_end();
+ for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
+ ++it) {
+ FunctionDecl* FD = *it;
+ switch (FD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ // We don't know what kind of FunctionDecl this is.
+ TRY_TO(TraverseDecl(FD));
+ break;
+
+ // No need to visit explicit instantiations, we'll find the node
+ // eventually.
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ break;
+
+ case TSK_ExplicitSpecialization:
+ break;
+ }
+ }
+
+ return true;
+}
+
+DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
+ TRY_TO(TraverseDecl(D->getTemplatedDecl()));
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+
+ // By default, we do not traverse the instantiations of
+ // function templates since they do not appear in the user code. The
+ // following code optionally traverses them.
+ //
+ // We only traverse the function instantiations when we see the canonical
+ // declaration of the template, to ensure we only visit them once.
+ if (getDerived().shouldVisitTemplateInstantiations() &&
+ D == D->getCanonicalDecl())
+ TRY_TO(TraverseFunctionInstantiations(D));
+ })
+
+DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
+ // D is the "T" in something like
+ // template <template <typename> class T> class container { };
+ TRY_TO(TraverseDecl(D->getTemplatedDecl()));
+ if (D->hasDefaultArgument()) {
+ TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
+ }
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+ })
+
+DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
+ // D is the "T" in something like "template<typename T> class vector;"
+ if (D->getTypeForDecl())
+ TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
+ if (D->hasDefaultArgument())
+ TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_DECL(TypedefDecl, {
+ TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+ // We shouldn't traverse D->getTypeForDecl(); it's a result of
+ // declaring the typedef, not something that was written in the
+ // source.
+ })
+
+DEF_TRAVERSE_DECL(TypeAliasDecl, {
+ TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+ // We shouldn't traverse D->getTypeForDecl(); it's a result of
+ // declaring the type alias, not something that was written in the
+ // source.
+ })
+
+DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, {
+ TRY_TO(TraverseDecl(D->getTemplatedDecl()));
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+ })
+
+DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
+ // A dependent using declaration which was marked with 'typename'.
+ // template<class T> class A : public B<T> { using typename B<T>::foo; };
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ // We shouldn't traverse D->getTypeForDecl(); it's a result of
+ // declaring the type, not something that was written in the
+ // source.
+ })
+
+DEF_TRAVERSE_DECL(EnumDecl, {
+ if (D->getTypeForDecl())
+ TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
+
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ // The enumerators are already traversed by
+ // decls_begin()/decls_end().
+ })
+
+
+// Helper methods for RecordDecl and its children.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(
+ RecordDecl *D) {
+ // We shouldn't traverse D->getTypeForDecl(); it's a result of
+ // declaring the type, not something that was written in the source.
+
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(
+ CXXRecordDecl *D) {
+ if (!TraverseRecordHelper(D))
+ return false;
+ if (D->isCompleteDefinition()) {
+ for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
+ E = D->bases_end();
+ I != E; ++I) {
+ TRY_TO(TraverseTypeLoc(I->getTypeSourceInfo()->getTypeLoc()));
+ }
+ // We don't traverse the friends or the conversions, as they are
+ // already in decls_begin()/decls_end().
+ }
+ return true;
+}
+
+DEF_TRAVERSE_DECL(RecordDecl, {
+ TRY_TO(TraverseRecordHelper(D));
+ })
+
+DEF_TRAVERSE_DECL(CXXRecordDecl, {
+ TRY_TO(TraverseCXXRecordHelper(D));
+ })
+
+DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, {
+ // For implicit instantiations ("set<int> x;"), we don't want to
+ // recurse at all, since the instatiated class isn't written in
+ // the source code anywhere. (Note the instatiated *type* --
+ // set<int> -- is written, and will still get a callback of
+ // TemplateSpecializationType). For explicit instantiations
+ // ("template set<int>;"), we do need a callback, since this
+ // is the only callback that's made for this instantiation.
+ // We use getTypeAsWritten() to distinguish.
+ if (TypeSourceInfo *TSI = D->getTypeAsWritten())
+ TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
+
+ if (!getDerived().shouldVisitTemplateInstantiations() &&
+ D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+ // Returning from here skips traversing the
+ // declaration context of the ClassTemplateSpecializationDecl
+ // (embedded in the DEF_TRAVERSE_DECL() macro)
+ // which contains the instantiated members of the class.
+ return true;
+ })
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
+ const TemplateArgumentLoc *TAL, unsigned Count) {
+ for (unsigned I = 0; I < Count; ++I) {
+ TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
+ }
+ return true;
+}
+
+DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
+ // The partial specialization.
+ if (TemplateParameterList *TPL = D->getTemplateParameters()) {
+ for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
+ I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ }
+ // The args that remains unspecialized.
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ D->getTemplateArgsAsWritten(), D->getNumTemplateArgsAsWritten()));
+
+ // Don't need the ClassTemplatePartialSpecializationHelper, even
+ // though that's our parent class -- we already visit all the
+ // template args here.
+ TRY_TO(TraverseCXXRecordHelper(D));
+
+ // Instantiations will have been visited with the primary template.
+ })
+
+DEF_TRAVERSE_DECL(EnumConstantDecl, {
+ TRY_TO(TraverseStmt(D->getInitExpr()));
+ })
+
+DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, {
+ // Like UnresolvedUsingTypenameDecl, but without the 'typename':
+ // template <class T> Class A : public Base<T> { using Base<T>::foo; };
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
+ })
+
+DEF_TRAVERSE_DECL(IndirectFieldDecl, {})
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ if (D->getTypeSourceInfo())
+ TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+ else
+ TRY_TO(TraverseType(D->getType()));
+ return true;
+}
+
+DEF_TRAVERSE_DECL(FieldDecl, {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ if (D->isBitField())
+ TRY_TO(TraverseStmt(D->getBitWidth()));
+ else if (D->hasInClassInitializer())
+ TRY_TO(TraverseStmt(D->getInClassInitializer()));
+ })
+
+DEF_TRAVERSE_DECL(ObjCAtDefsFieldDecl, {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ if (D->isBitField())
+ TRY_TO(TraverseStmt(D->getBitWidth()));
+ // FIXME: implement the rest.
+ })
+
+DEF_TRAVERSE_DECL(ObjCIvarDecl, {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ if (D->isBitField())
+ TRY_TO(TraverseStmt(D->getBitWidth()));
+ // FIXME: implement the rest.
+ })
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
+
+ // If we're an explicit template specialization, iterate over the
+ // template args that were explicitly specified. If we were doing
+ // this in typing order, we'd do it between the return type and
+ // the function args, but both are handled by the FunctionTypeLoc
+ // above, so we have to choose one side. I've decided to do before.
+ if (const FunctionTemplateSpecializationInfo *FTSI =
+ D->getTemplateSpecializationInfo()) {
+ if (FTSI->getTemplateSpecializationKind() != TSK_Undeclared &&
+ FTSI->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
+ // A specialization might not have explicit template arguments if it has
+ // a templated return type and concrete arguments.
+ if (const ASTTemplateArgumentListInfo *TALI =
+ FTSI->TemplateArgumentsAsWritten) {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(),
+ TALI->NumTemplateArgs));
+ }
+ }
+ }
+
+ // Visit the function type itself, which can be either
+ // FunctionNoProtoType or FunctionProtoType, or a typedef. This
+ // also covers the return type and the function parameters,
+ // including exception specifications.
+ TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+
+ if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
+ // Constructor initializers.
+ for (CXXConstructorDecl::init_iterator I = Ctor->init_begin(),
+ E = Ctor->init_end();
+ I != E; ++I) {
+ TRY_TO(TraverseConstructorInitializer(*I));
+ }
+ }
+
+ if (D->isThisDeclarationADefinition()) {
+ TRY_TO(TraverseStmt(D->getBody())); // Function body.
+ }
+ return true;
+}
+
+DEF_TRAVERSE_DECL(FunctionDecl, {
+ // We skip decls_begin/decls_end, which are already covered by
+ // TraverseFunctionHelper().
+ return TraverseFunctionHelper(D);
+ })
+
+DEF_TRAVERSE_DECL(CXXMethodDecl, {
+ // We skip decls_begin/decls_end, which are already covered by
+ // TraverseFunctionHelper().
+ return TraverseFunctionHelper(D);
+ })
+
+DEF_TRAVERSE_DECL(CXXConstructorDecl, {
+ // We skip decls_begin/decls_end, which are already covered by
+ // TraverseFunctionHelper().
+ return TraverseFunctionHelper(D);
+ })
+
+// CXXConversionDecl is the declaration of a type conversion operator.
+// It's not a cast expression.
+DEF_TRAVERSE_DECL(CXXConversionDecl, {
+ // We skip decls_begin/decls_end, which are already covered by
+ // TraverseFunctionHelper().
+ return TraverseFunctionHelper(D);
+ })
+
+DEF_TRAVERSE_DECL(CXXDestructorDecl, {
+ // We skip decls_begin/decls_end, which are already covered by
+ // TraverseFunctionHelper().
+ return TraverseFunctionHelper(D);
+ })
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ // Default params are taken care of when we traverse the ParmVarDecl.
+ if (!isa<ParmVarDecl>(D))
+ TRY_TO(TraverseStmt(D->getInit()));
+ return true;
+}
+
+DEF_TRAVERSE_DECL(VarDecl, {
+ TRY_TO(TraverseVarHelper(D));
+ })
+
+DEF_TRAVERSE_DECL(ImplicitParamDecl, {
+ TRY_TO(TraverseVarHelper(D));
+ })
+
+DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
+ // A non-type template parameter, e.g. "S" in template<int S> class Foo ...
+ TRY_TO(TraverseDeclaratorHelper(D));
+ TRY_TO(TraverseStmt(D->getDefaultArgument()));
+ })
+
+DEF_TRAVERSE_DECL(ParmVarDecl, {
+ TRY_TO(TraverseVarHelper(D));
+
+ if (D->hasDefaultArg() &&
+ D->hasUninstantiatedDefaultArg() &&
+ !D->hasUnparsedDefaultArg())
+ TRY_TO(TraverseStmt(D->getUninstantiatedDefaultArg()));
+
+ if (D->hasDefaultArg() &&
+ !D->hasUninstantiatedDefaultArg() &&
+ !D->hasUnparsedDefaultArg())
+ TRY_TO(TraverseStmt(D->getDefaultArg()));
+ })
+
+#undef DEF_TRAVERSE_DECL
+
+// ----------------- Stmt traversal -----------------
+//
+// For stmts, we automate (in the DEF_TRAVERSE_STMT macro) iterating
+// over the children defined in children() (every stmt defines these,
+// though sometimes the range is empty). Each individual Traverse*
+// method only needs to worry about children other than those. To see
+// what children() does for a given class, see, e.g.,
+// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html
+
+// This macro makes available a variable S, the passed-in stmt.
+#define DEF_TRAVERSE_STMT(STMT, CODE) \
+template<typename Derived> \
+bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \
+ TRY_TO(WalkUpFrom##STMT(S)); \
+ StmtQueueAction StmtQueue(*this); \
+ { CODE; } \
+ for (Stmt::child_range range = S->children(); range; ++range) { \
+ StmtQueue.queue(*range); \
+ } \
+ return true; \
+}
+
+DEF_TRAVERSE_STMT(AsmStmt, {
+ StmtQueue.queue(S->getAsmString());
+ for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
+ StmtQueue.queue(S->getInputConstraintLiteral(I));
+ }
+ for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) {
+ StmtQueue.queue(S->getOutputConstraintLiteral(I));
+ }
+ for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
+ StmtQueue.queue(S->getClobber(I));
+ }
+ // children() iterates over inputExpr and outputExpr.
+ })
+
+DEF_TRAVERSE_STMT(MSAsmStmt, {
+ // FIXME: MS Asm doesn't currently parse Constraints, Clobbers, etc. Once
+ // added this needs to be implemented.
+ })
+
+DEF_TRAVERSE_STMT(CXXCatchStmt, {
+ TRY_TO(TraverseDecl(S->getExceptionDecl()));
+ // children() iterates over the handler block.
+ })
+
+DEF_TRAVERSE_STMT(DeclStmt, {
+ for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();
+ I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ // Suppress the default iteration over children() by
+ // returning. Here's why: A DeclStmt looks like 'type var [=
+ // initializer]'. The decls above already traverse over the
+ // initializers, so we don't have to do it again (which
+ // children() would do).
+ return true;
+ })
+
+
+// These non-expr stmts (most of them), do not need any action except
+// iterating over the children.
+DEF_TRAVERSE_STMT(BreakStmt, { })
+DEF_TRAVERSE_STMT(CXXTryStmt, { })
+DEF_TRAVERSE_STMT(CaseStmt, { })
+DEF_TRAVERSE_STMT(CompoundStmt, { })
+DEF_TRAVERSE_STMT(ContinueStmt, { })
+DEF_TRAVERSE_STMT(DefaultStmt, { })
+DEF_TRAVERSE_STMT(DoStmt, { })
+DEF_TRAVERSE_STMT(ForStmt, { })
+DEF_TRAVERSE_STMT(GotoStmt, { })
+DEF_TRAVERSE_STMT(IfStmt, { })
+DEF_TRAVERSE_STMT(IndirectGotoStmt, { })
+DEF_TRAVERSE_STMT(LabelStmt, { })
+DEF_TRAVERSE_STMT(AttributedStmt, { })
+DEF_TRAVERSE_STMT(NullStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtCatchStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtFinallyStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
+DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
+DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { })
+DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
+DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
+})
+DEF_TRAVERSE_STMT(ReturnStmt, { })
+DEF_TRAVERSE_STMT(SwitchStmt, { })
+DEF_TRAVERSE_STMT(WhileStmt, { })
+
+
+DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
+ if (S->hasExplicitTemplateArgs()) {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getTemplateArgs(), S->getNumTemplateArgs()));
+ }
+ })
+
+DEF_TRAVERSE_STMT(DeclRefExpr, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getTemplateArgs(), S->getNumTemplateArgs()));
+ })
+
+DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
+ if (S->hasExplicitTemplateArgs()) {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getExplicitTemplateArgs().getTemplateArgs(),
+ S->getNumTemplateArgs()));
+ }
+ })
+
+DEF_TRAVERSE_STMT(MemberExpr, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getTemplateArgs(), S->getNumTemplateArgs()));
+ })
+
+DEF_TRAVERSE_STMT(ImplicitCastExpr, {
+ // We don't traverse the cast type, as it's not written in the
+ // source code.
+ })
+
+DEF_TRAVERSE_STMT(CStyleCastExpr, {
+ TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXFunctionalCastExpr, {
+ TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXConstCastExpr, {
+ TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXDynamicCastExpr, {
+ TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXReinterpretCastExpr, {
+ TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
+ TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+ })
+
+// InitListExpr is a tricky one, because we want to do all our work on
+// the syntactic form of the listexpr, but this method takes the
+// semantic form by default. We can't use the macro helper because it
+// calls WalkUp*() on the semantic form, before our code can convert
+// to the syntactic form.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
+ if (InitListExpr *Syn = S->getSyntacticForm())
+ S = Syn;
+ TRY_TO(WalkUpFromInitListExpr(S));
+ StmtQueueAction StmtQueue(*this);
+ // All we need are the default actions. FIXME: use a helper function.
+ for (Stmt::child_range range = S->children(); range; ++range) {
+ StmtQueue.queue(*range);
+ }
+ return true;
+}
+
+// GenericSelectionExpr is a special case because the types and expressions
+// are interleaved. We also need to watch out for null types (default
+// generic associations).
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::
+TraverseGenericSelectionExpr(GenericSelectionExpr *S) {
+ TRY_TO(WalkUpFromGenericSelectionExpr(S));
+ StmtQueueAction StmtQueue(*this);
+ StmtQueue.queue(S->getControllingExpr());
+ for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
+ if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i))
+ TRY_TO(TraverseTypeLoc(TS->getTypeLoc()));
+ StmtQueue.queue(S->getAssocExpr(i));
+ }
+ return true;
+}
+
+// PseudoObjectExpr is a special case because of the wierdness with
+// syntactic expressions and opaque values.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::
+TraversePseudoObjectExpr(PseudoObjectExpr *S) {
+ TRY_TO(WalkUpFromPseudoObjectExpr(S));
+ StmtQueueAction StmtQueue(*this);
+ StmtQueue.queue(S->getSyntacticForm());
+ for (PseudoObjectExpr::semantics_iterator
+ i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) {
+ Expr *sub = *i;
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
+ sub = OVE->getSourceExpr();
+ StmtQueue.queue(sub);
+ }
+ return true;
+}
+
+DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
+ // This is called for code like 'return T()' where T is a built-in
+ // (i.e. non-class) type.
+ TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXNewExpr, {
+ // The child-iterator will pick up the other arguments.
+ TRY_TO(TraverseTypeLoc(S->getAllocatedTypeSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(OffsetOfExpr, {
+ // The child-iterator will pick up the expression representing
+ // the field.
+ // FIMXE: for code like offsetof(Foo, a.b.c), should we get
+ // making a MemberExpr callbacks for Foo.a, Foo.a.b, and Foo.a.b.c?
+ TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(UnaryExprOrTypeTraitExpr, {
+ // The child-iterator will pick up the arg if it's an expression,
+ // but not if it's a type.
+ if (S->isArgumentType())
+ TRY_TO(TraverseTypeLoc(S->getArgumentTypeInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXTypeidExpr, {
+ // The child-iterator will pick up the arg if it's an expression,
+ // but not if it's a type.
+ if (S->isTypeOperand())
+ TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXUuidofExpr, {
+ // The child-iterator will pick up the arg if it's an expression,
+ // but not if it's a type.
+ if (S->isTypeOperand())
+ TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(UnaryTypeTraitExpr, {
+ TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, {
+ TRY_TO(TraverseTypeLoc(S->getLhsTypeSourceInfo()->getTypeLoc()));
+ TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(TypeTraitExpr, {
+ for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I)
+ TRY_TO(TraverseTypeLoc(S->getArg(I)->getTypeLoc()));
+})
+
+DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, {
+ TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(ExpressionTraitExpr, {
+ StmtQueue.queue(S->getQueriedExpression());
+ })
+
+DEF_TRAVERSE_STMT(VAArgExpr, {
+ // The child-iterator will pick up the expression argument.
+ TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
+ // This is called for code like 'return T()' where T is a class type.
+ TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
+ })
+
+// Walk only the visible parts of lambda expressions.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
+ for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
+ CEnd = S->explicit_capture_end();
+ C != CEnd; ++C) {
+ TRY_TO(TraverseLambdaCapture(*C));
+ }
+
+ if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
+ TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
+ // Visit the whole type.
+ TRY_TO(TraverseTypeLoc(TL));
+ } else if (isa<FunctionProtoTypeLoc>(TL)) {
+ FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ if (S->hasExplicitParameters()) {
+ // Visit parameters.
+ for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) {
+ TRY_TO(TraverseDecl(Proto.getArg(I)));
+ }
+ } else {
+ TRY_TO(TraverseTypeLoc(Proto.getResultLoc()));
+ }
+ }
+ }
+
+ StmtQueueAction StmtQueue(*this);
+ StmtQueue.queue(S->getBody());
+ return true;
+}
+
+DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
+ // This is called for code like 'T()', where T is a template argument.
+ TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
+ })
+
+// These expressions all might take explicit template arguments.
+// We traverse those if so. FIXME: implement these.
+DEF_TRAVERSE_STMT(CXXConstructExpr, { })
+DEF_TRAVERSE_STMT(CallExpr, { })
+DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
+
+// These exprs (most of them), do not need any action except iterating
+// over the children.
+DEF_TRAVERSE_STMT(AddrLabelExpr, { })
+DEF_TRAVERSE_STMT(ArraySubscriptExpr, { })
+DEF_TRAVERSE_STMT(BlockExpr, {
+ TRY_TO(TraverseDecl(S->getBlockDecl()));
+ return true; // no child statements to loop through.
+})
+DEF_TRAVERSE_STMT(ChooseExpr, { })
+DEF_TRAVERSE_STMT(CompoundLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
+DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
+DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
+DEF_TRAVERSE_STMT(ExprWithCleanups, { })
+DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
+ TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc()));
+ if (TypeSourceInfo *DestroyedTypeInfo = S->getDestroyedTypeInfo())
+ TRY_TO(TraverseTypeLoc(DestroyedTypeInfo->getTypeLoc()));
+})
+DEF_TRAVERSE_STMT(CXXThisExpr, { })
+DEF_TRAVERSE_STMT(CXXThrowExpr, { })
+DEF_TRAVERSE_STMT(UserDefinedLiteral, { })
+DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
+DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
+DEF_TRAVERSE_STMT(GNUNullExpr, { })
+DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { })
+DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, { })
+DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
+ if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())
+ TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
+})
+DEF_TRAVERSE_STMT(ObjCIsaExpr, { })
+DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { })
+DEF_TRAVERSE_STMT(ObjCMessageExpr, { })
+DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { })
+DEF_TRAVERSE_STMT(ObjCSubscriptRefExpr, { })
+DEF_TRAVERSE_STMT(ObjCProtocolExpr, { })
+DEF_TRAVERSE_STMT(ObjCSelectorExpr, { })
+DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, { })
+DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, {
+ TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+})
+DEF_TRAVERSE_STMT(ParenExpr, { })
+DEF_TRAVERSE_STMT(ParenListExpr, { })
+DEF_TRAVERSE_STMT(PredefinedExpr, { })
+DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
+DEF_TRAVERSE_STMT(StmtExpr, { })
+DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ if (S->hasExplicitTemplateArgs()) {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
+ S->getNumTemplateArgs()));
+ }
+})
+
+DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ if (S->hasExplicitTemplateArgs()) {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
+ S->getNumTemplateArgs()));
+ }
+})
+
+DEF_TRAVERSE_STMT(SEHTryStmt, {})
+DEF_TRAVERSE_STMT(SEHExceptStmt, {})
+DEF_TRAVERSE_STMT(SEHFinallyStmt,{})
+
+DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
+DEF_TRAVERSE_STMT(OpaqueValueExpr, { })
+DEF_TRAVERSE_STMT(CUDAKernelCallExpr, { })
+
+// These operators (all of them) do not need any action except
+// iterating over the children.
+DEF_TRAVERSE_STMT(BinaryConditionalOperator, { })
+DEF_TRAVERSE_STMT(ConditionalOperator, { })
+DEF_TRAVERSE_STMT(UnaryOperator, { })
+DEF_TRAVERSE_STMT(BinaryOperator, { })
+DEF_TRAVERSE_STMT(CompoundAssignOperator, { })
+DEF_TRAVERSE_STMT(CXXNoexceptExpr, { })
+DEF_TRAVERSE_STMT(PackExpansionExpr, { })
+DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
+DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
+DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
+DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
+DEF_TRAVERSE_STMT(AtomicExpr, { })
+
+// These literals (all of them) do not need any action.
+DEF_TRAVERSE_STMT(IntegerLiteral, { })
+DEF_TRAVERSE_STMT(CharacterLiteral, { })
+DEF_TRAVERSE_STMT(FloatingLiteral, { })
+DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
+DEF_TRAVERSE_STMT(StringLiteral, { })
+DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
+DEF_TRAVERSE_STMT(ObjCBoxedExpr, { })
+DEF_TRAVERSE_STMT(ObjCArrayLiteral, { })
+DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
+
+// Traverse OpenCL: AsType, Convert.
+DEF_TRAVERSE_STMT(AsTypeExpr, { })
+
+// FIXME: look at the following tricky-seeming exprs to see if we
+// need to recurse on anything. These are ones that have methods
+// returning decls or qualtypes or nestednamespecifier -- though I'm
+// not sure if they own them -- or just seemed very complicated, or
+// had lots of sub-types to explore.
+//
+// VisitOverloadExpr and its children: recurse on template args? etc?
+
+// FIXME: go through all the stmts and exprs again, and see which of them
+// create new types, and recurse on the types (TypeLocs?) of those.
+// Candidates:
+//
+// http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html
+// http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html
+// http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html
+// Every class that has getQualifier.
+
+#undef DEF_TRAVERSE_STMT
+
+#undef TRY_TO
+
+} // end namespace cxindex
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIBCLANG_RECURSIVEASTVISITOR_H
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index d3b64db..610bd91 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -5,14 +5,52 @@ clang_CXIndex_setGlobalOptions
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
clang_Cursor_getArgument
+clang_Cursor_getBriefCommentText
+clang_Cursor_getCommentRange
+clang_Cursor_getParsedComment
+clang_Cursor_getRawCommentText
clang_Cursor_getNumArguments
clang_Cursor_getObjCSelectorIndex
clang_Cursor_getSpellingNameRange
clang_Cursor_getTranslationUnit
+clang_Cursor_isDynamicCall
clang_Cursor_isNull
clang_IndexAction_create
clang_IndexAction_dispose
clang_Range_isNull
+clang_Comment_getKind
+clang_Comment_getNumChildren
+clang_Comment_getChild
+clang_Comment_isWhitespace
+clang_InlineContentComment_hasTrailingNewline
+clang_TextComment_getText
+clang_InlineCommandComment_getCommandName
+clang_InlineCommandComment_getRenderKind
+clang_InlineCommandComment_getNumArgs
+clang_InlineCommandComment_getArgText
+clang_HTMLTagComment_getTagName
+clang_HTMLStartTagComment_isSelfClosing
+clang_HTMLStartTag_getNumAttrs
+clang_HTMLStartTag_getAttrName
+clang_HTMLStartTag_getAttrValue
+clang_BlockCommandComment_getCommandName
+clang_BlockCommandComment_getNumArgs
+clang_BlockCommandComment_getArgText
+clang_BlockCommandComment_getParagraph
+clang_ParamCommandComment_getParamName
+clang_ParamCommandComment_isParamIndexValid
+clang_ParamCommandComment_getParamIndex
+clang_ParamCommandComment_isDirectionExplicit
+clang_ParamCommandComment_getDirection
+clang_TParamCommandComment_getParamName
+clang_TParamCommandComment_isParamPositionValid
+clang_TParamCommandComment_getDepth
+clang_TParamCommandComment_getIndex
+clang_VerbatimBlockLineComment_getText
+clang_VerbatimLineComment_getText
+clang_HTMLTagComment_getAsString
+clang_FullComment_getAsHTML
+clang_FullComment_getAsXML
clang_annotateTokens
clang_codeCompleteAt
clang_codeCompleteGetContainerKind
@@ -43,6 +81,7 @@ clang_disposeDiagnostic
clang_disposeDiagnosticSet
clang_disposeIndex
clang_disposeOverriddenCursors
+clang_disposeCXPlatformAvailability
clang_disposeString
clang_disposeTokens
clang_disposeTranslationUnit
@@ -67,6 +106,7 @@ clang_getChildDiagnostics
clang_getClangVersion
clang_getCompletionAnnotation
clang_getCompletionAvailability
+clang_getCompletionBriefComment
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
@@ -85,6 +125,7 @@ clang_getCursorLanguage
clang_getCursorLexicalParent
clang_getCursorLinkage
clang_getCursorLocation
+clang_getCursorPlatformAvailability
clang_getCursorReferenceNameRange
clang_getCursorReferenced
clang_getCursorResultType
@@ -199,5 +240,14 @@ clang_saveTranslationUnit
clang_sortCodeCompletionResults
clang_toggleCrashRecovery
clang_tokenize
+clang_CompilationDatabase_fromDirectory
+clang_CompilationDatabase_dispose
+clang_CompilationDatabase_getCompileCommands
+clang_CompileCommands_dispose
+clang_CompileCommands_getSize
+clang_CompileCommands_getCommand
+clang_CompileCommand_getDirectory
+clang_CompileCommand_getNumArgs
+clang_CompileCommand_getArg
clang_visitChildren
clang_visitChildrenWithBlock
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index d01bd0f..c7636f9 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -182,11 +182,6 @@ sub Analyze {
}
else {
$Cmd = $Clang;
- if ($Lang eq "objective-c" || $Lang eq "objective-c++") {
- push @Args,'-DIBOutlet=__attribute__((iboutlet))';
- push @Args,'-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection)))';
- push @Args,'-DIBAction=void)__attribute__((ibaction)';
- }
# Create arguments for doing regular parsing.
my $SyntaxArgs = GetCCArgs("-fsyntax-only", \@Args);
@@ -352,6 +347,8 @@ my %LinkerOptionMap = (
my %CompilerLinkerOptionMap = (
'-fobjc-arc' => 0,
'-fobjc-abi-version' => 0, # This is really a 1 argument, but always has '='
+ '-fobjc-legacy-dispatch' => 0,
+ '-mios-simulator-version-min' => 0, # This really has 1 argument, but always has '='
'-isysroot' => 1,
'-arch' => 1,
'-m32' => 0,
@@ -434,12 +431,18 @@ if ($Status) { exit($Status >> 8); }
# Get the analysis options.
my $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'};
+# Get the plugins to load.
+my $Plugins = $ENV{'CCC_ANALYZER_PLUGINS'};
+
# Get the store model.
my $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'};
# Get the constraints engine.
my $ConstraintsModel = $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'};
+#Get the internal stats setting.
+my $InternalStats = $ENV{'CCC_ANALYZER_INTERNAL_STATS'};
+
# Get the output format.
my $OutputFormat = $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'};
if (!defined $OutputFormat) { $OutputFormat = "html"; }
@@ -644,11 +647,19 @@ if ($Action eq 'compile' or $Action eq 'link') {
if (defined $ConstraintsModel) {
push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel";
}
+
+ if (defined $InternalStats) {
+ push @AnalyzeArgs, "-analyzer-stats";
+ }
if (defined $Analyses) {
push @AnalyzeArgs, split '\s+', $Analyses;
}
+ if (defined $Plugins) {
+ push @AnalyzeArgs, split '\s+', $Plugins;
+ }
+
if (defined $OutputFormat) {
push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;
if ($OutputFormat =~ /plist/) {
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index 59b0baf..65c4893 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -28,7 +28,7 @@ my $BuildName;
my $BuildDate;
my $TERM = $ENV{'TERM'};
-my $UseColor = (defined $TERM and $TERM eq 'xterm-color' and -t STDOUT
+my $UseColor = (defined $TERM and $TERM =~ 'xterm-.*color' and -t STDOUT
and defined $ENV{'SCAN_BUILD_COLOR'});
my $UserName = HtmlEscape(getpwuid($<) || 'unknown');
@@ -36,6 +36,7 @@ my $HostName = HtmlEscape(hostname() || 'unknown');
my $CurrentDir = HtmlEscape(getcwd());
my $CurrentDirSuffix = basename($CurrentDir);
+my @PluginsToLoad;
my $CmdArgs;
my $HtmlTitle;
@@ -77,6 +78,21 @@ sub DieDiag {
}
##----------------------------------------------------------------------------##
+# Print default checker names
+##----------------------------------------------------------------------------##
+
+if (grep /^--help-checkers$/, @ARGV) {
+ my @options = qx($0 -h);
+ foreach (@options) {
+ next unless /^ \+/;
+ s/^\s*//;
+ my ($sign, $name, @text) = split ' ', $_;
+ print $name, $/ if $sign eq '+';
+ }
+ exit 1;
+}
+
+##----------------------------------------------------------------------------##
# Some initial preprocessing of Clang options.
##----------------------------------------------------------------------------##
@@ -91,13 +107,16 @@ if (!defined $ClangSB || ! -x $ClangSB) {
$Clang = `which clang`;
chomp $Clang;
if ($Clang eq "") {
- DieDiag("No 'clang' executable found in path.");
+ DieDiag("No 'clang' executable found in path.\n");
}
}
else {
$Clang = $ClangSB;
}
-my $ClangCXX = $Clang . "++";
+my $ClangCXX = $Clang;
+$ClangCXX =~ s/\-\d+\.\d+$//;
+$ClangCXX .= "++";
+my $ClangVersion = HtmlEscape(`$Clang --version`);
##----------------------------------------------------------------------------##
# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
@@ -590,6 +609,7 @@ function ToggleDisplay(CheckButton, ClassName) {
<tr><th>User:</th><td>${UserName}\@${HostName}</td></tr>
<tr><th>Working Directory:</th><td>${CurrentDir}</td></tr>
<tr><th>Command Line:</th><td>${CmdArgs}</td></tr>
+<tr><th>Clang Version:</th><td>${ClangVersion}</td></tr>
<tr><th>Date:</th><td>${Date}</td></tr>
ENDTEXT
@@ -848,19 +868,87 @@ sub AddIfNotPresent {
}
}
-sub RunBuildCommand {
+sub SetEnv {
+ my $Options = shift @_;
+ foreach my $opt ('CC', 'CXX', 'CLANG', 'CLANG_CXX',
+ 'CCC_ANALYZER_ANALYSIS', 'CCC_ANALYZER_PLUGINS') {
+ die "$opt is undefined\n" if (!defined $opt);
+ $ENV{$opt} = $Options->{$opt};
+ }
+ foreach my $opt ('CCC_ANALYZER_STORE_MODEL',
+ 'CCC_ANALYZER_PLUGINS',
+ 'CCC_ANALYZER_INTERNAL_STATS',
+ 'CCC_ANALYZER_OUTPUT_FORMAT') {
+ my $x = $Options->{$opt};
+ if (defined $x) { $ENV{$opt} = $x }
+ }
+ my $Verbose = $Options->{'VERBOSE'};
+ if ($Verbose >= 2) {
+ $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
+ }
+ if ($Verbose >= 3) {
+ $ENV{'CCC_ANALYZER_LOG'} = 1;
+ }
+}
+
+sub RunXcodebuild {
+ my $Args = shift;
+ my $IgnoreErrors = shift;
+ my $CCAnalyzer = shift;
+ my $CXXAnalyzer = shift;
+ my $Options = shift;
+
+ if ($IgnoreErrors) {
+ AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
+ }
+
+ # Default to old behavior where we insert a bogus compiler.
+ SetEnv($Options);
+
+ # Check if using iPhone SDK 3.0 (simulator). If so the compiler being
+ # used should be gcc-4.2.
+ if (!defined $ENV{"CCC_CC"}) {
+ for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
+ if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
+ if (@$Args[$i+1] =~ /^iphonesimulator3/) {
+ $ENV{"CCC_CC"} = "gcc-4.2";
+ $ENV{"CCC_CXX"} = "g++-4.2";
+ }
+ }
+ }
+ }
+
+ # Disable PCH files until clang supports them.
+ AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
+ # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
+ # linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
+ # (via c++-analyzer) when linking such files.
+ $ENV{"LDPLUSPLUS"} = $CXXAnalyzer;
+
+ return (system(@$Args) >> 8);
+}
+
+sub RunBuildCommand {
my $Args = shift;
my $IgnoreErrors = shift;
my $Cmd = $Args->[0];
my $CCAnalyzer = shift;
my $CXXAnalyzer = shift;
+ my $Options = shift;
# Get only the part of the command after the last '/'.
if ($Cmd =~ /\/([^\/]+)$/) {
$Cmd = $1;
}
+ if ($Cmd eq "xcodebuild") {
+ return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $Options);
+ }
+
+ # Setup the environment.
+ SetEnv($Options);
+
if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or
$Cmd =~ /(.*\/?cc[^\/]*$)/ or
$Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or
@@ -892,34 +980,8 @@ sub RunBuildCommand {
AddIfNotPresent($Args,"-k");
AddIfNotPresent($Args,"-i");
}
- elsif ($Cmd eq "xcodebuild") {
- AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
- }
}
-
- if ($Cmd eq "xcodebuild") {
- # Check if using iPhone SDK 3.0 (simulator). If so the compiler being
- # used should be gcc-4.2.
- if (!defined $ENV{"CCC_CC"}) {
- for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
- if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
- if (@$Args[$i+1] =~ /^iphonesimulator3/) {
- $ENV{"CCC_CC"} = "gcc-4.2";
- $ENV{"CCC_CXX"} = "g++-4.2";
- }
- }
- }
- }
- # Disable PCH files until clang supports them.
- AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
-
- # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
- # linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
- # (via c++-analyzer) when linking such files.
- $ENV{"LDPLUSPLUS"} = $CXXAnalyzer;
- }
-
return (system(@$Args) >> 8);
}
@@ -1007,7 +1069,8 @@ ADVANCED OPTIONS:
-maxloop N - specifiy the number of times a block can be visited before giving
up. Default is 4. Increase for more comprehensive coverage at a
cost of speed.
-
+ -internal-stats - Generate internal analyzer statistics.
+
CONTROLLING CHECKERS:
A default group of checkers are always run unless explicitly disabled.
@@ -1015,9 +1078,23 @@ CONTROLLING CHECKERS:
-enable-checker [checker name]
-disable-checker [checker name]
+
+LOADING CHECKERS:
+
+ Loading external checkers using the clang plugin interface:
+
+ -load-plugin [plugin library]
ENDTEXT
# Query clang for list of checkers that are enabled.
+
+# create a list to load the plugins via the 'Xclang' command line
+# argument
+my @PluginLoadCommandline_xclang;
+foreach my $param ( @PluginsToLoad ) {
+ push ( @PluginLoadCommandline_xclang, "-Xclang" );
+ push ( @PluginLoadCommandline_xclang, $param );
+}
my %EnabledCheckers;
foreach my $lang ("c", "objective-c", "objective-c++", "c++") {
pipe(FROM_CHILD, TO_PARENT);
@@ -1026,7 +1103,7 @@ foreach my $lang ("c", "objective-c", "objective-c++", "c++") {
close FROM_CHILD;
open(STDOUT,">&", \*TO_PARENT);
open(STDERR,">&", \*TO_PARENT);
- exec $Clang, ('--analyze', '-x', $lang, '-', '-###');
+ exec $Clang, ( @PluginLoadCommandline_xclang, '--analyze', '-x', $lang, '-', '-###');
}
close(TO_PARENT);
while(<FROM_CHILD>) {
@@ -1048,7 +1125,7 @@ if ($pid == 0) {
close FROM_CHILD;
open(STDOUT,">&", \*TO_PARENT);
open(STDERR,">&", \*TO_PARENT);
- exec $Clang, ('-cc1', '-analyzer-checker-help');
+ exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
}
close(TO_PARENT);
my $foundCheckers = 0;
@@ -1084,7 +1161,9 @@ else {
if ($EnabledCheckers{$aggregate}) {
$enabled =1;
last;
- }
+ }
+ # append a dot, if an additional domain is added in the next iteration
+ $aggregate .= ".";
}
if ($enabled) {
@@ -1160,6 +1239,7 @@ my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
my @AnalysesToRun;
my $StoreModel;
my $ConstraintsModel;
+my $InternalStats;
my $OutputFormat = "html";
my $AnalyzerStats = 0;
my $MaxLoop = 0;
@@ -1291,6 +1371,12 @@ while (@ARGV) {
$ConstraintsModel = shift @ARGV;
next;
}
+
+ if ($arg eq "-internal-stats") {
+ shift @ARGV;
+ $InternalStats = 1;
+ next;
+ }
if ($arg eq "-plist") {
shift @ARGV;
@@ -1327,7 +1413,12 @@ while (@ARGV) {
push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV;
next;
}
-
+ if ($arg eq "-load-plugin") {
+ shift @ARGV;
+ push @PluginsToLoad, "-load", shift @ARGV;
+ next;
+ }
+
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
last;
@@ -1371,42 +1462,42 @@ if (!defined $ClangSB || ! -x $ClangSB) {
Diag("Using 'clang' from path: $Clang\n");
}
-# Set the appropriate environment variables.
SetHtmlEnv(\@ARGV, $HtmlDir);
-$ENV{'CC'} = $Cmd;
-$ENV{'CXX'} = $CmdCXX;
-$ENV{'CLANG'} = $Clang;
-$ENV{'CLANG_CXX'} = $ClangCXX;
-if ($Verbose >= 2) {
- $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
-}
-if ($Verbose >= 3) {
- $ENV{'CCC_ANALYZER_LOG'} = 1;
-}
-if ($AnalyzeHeaders) {
- push @AnalysesToRun,"-analyzer-opt-analyze-headers";
-}
-if ($AnalyzerStats) {
- push @AnalysesToRun, '-analyzer-checker', 'debug.Stats';
-}
-if ($MaxLoop > 0) {
- push @AnalysesToRun, '-analyzer-max-loop ' . $MaxLoop;
-}
-
-$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
+if ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; }
+if ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; }
+if ($MaxLoop > 0) { push @AnalysesToRun, '-analyzer-max-loop=$MaxLoop'; }
+
+# Delay setting up other environment variables in case we can do true
+# interposition.
+my $CCC_ANALYZER_ANALYSIS = join ' ',@AnalysesToRun;
+my $CCC_ANALYZER_PLUGINS = join ' ',@PluginsToLoad;
+my %Options = (
+ 'CC' => $Cmd,
+ 'CXX' => $CmdCXX,
+ 'CLANG' => $Clang,
+ 'CLANG_CXX' => $ClangCXX,
+ 'VERBOSE' => $Verbose,
+ 'CCC_ANALYZER_ANALYSIS' => $CCC_ANALYZER_ANALYSIS,
+ 'CCC_ANALYZER_PLUGINS' => $CCC_ANALYZER_PLUGINS,
+ 'OUTPUT_DIR' => $HtmlDir
+);
if (defined $StoreModel) {
- $ENV{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
+ $Options{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
}
if (defined $ConstraintsModel) {
- $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
+ $Options{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
+}
+if (defined $InternalStats) {
+ $Options{'CCC_ANALYZER_INTERNAL_STATS'} = 1;
}
if (defined $OutputFormat) {
- $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
+ $Options{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
}
# Run the build.
-my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX);
+my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX,
+ \%Options);
if (defined $OutputFormat) {
if ($OutputFormat =~ /plist/) {
diff --git a/tools/scan-build/scan-build.1 b/tools/scan-build/scan-build.1
new file mode 100644
index 0000000..0f43196
--- /dev/null
+++ b/tools/scan-build/scan-build.1
@@ -0,0 +1,348 @@
+.\" This file is distributed under the University of Illinois Open Source
+.\" License. See LICENSE.TXT for details.
+.\" $Id: scan-build.1 157412 2012-05-24 20:16:00Z kremenek $
+.Dd May 25, 2012
+.Os "clang" "3.1"
+.Dt SCAN-BUILD \&1 CLANG
+.Sh NAME
+.Nm scan-build
+.Nd Clang static analyzer
+.Sh SYNOPSIS
+.Nm
+.Op Fl ohkvV
+.Op Fl analyze-headers
+.Op Fl enable-checker Op Ar checker_name
+.Op Fl disable-checker Op Ar checker_name
+.Op Fl Fl help
+.Op Fl Fl help-checkers
+.Op Fl Fl html-title Op Ar =title
+.Op Fl Fl keep-going
+.Op Fl plist
+.Op Fl plist-html
+.Op Fl Fl status-bugs
+.Op Fl Fl use-c++ Op Ar =compiler_path
+.Op Fl Fl use-cc Op Ar =compiler_path
+.Op Fl Fl view
+.Op Fl constraints Op Ar model
+.Op Fl maxloop Ar N
+.Op Fl no-failure-reports
+.Op Fl stats
+.Op Fl store Op Ar model
+.Ar build_command
+.Op build_options
+.\"
+.\" Sh DESCRIPTION
+.Sh DESCRIPTION
+.Nm
+is a Perl script that invokes the Clang static analyzer. Options used by
+.Nm
+or by the analyzer appear first, followed by the
+.Ar build_command
+and any
+.Ar build_options
+normally used to build the target system.
+.Pp
+The static analyzer employs a long list of checking algorithms, see
+.Sx CHECKERS .
+Output can be written in standard
+.Li .plist
+and/or HTML format.
+.Pp
+The following options are supported:
+.Bl -tag -width indent
+.It Fl analyze-headers
+Also analyze functions in #included files.
+.It Fl enable-checker Ar checker_name , Fl disable-checker Ar checker_name
+Enable/disable
+.Ar checker_name .
+See
+.Sx CHECKERS .
+.It Fl h , Fl Fl help
+Display this message.
+.It Fl Fl help-checkers
+List default checkers, see
+.Sx CHECKERS .
+.It Fl Fl html-title Ns Op = Ns Ar title
+Specify the title used on generated HTML pages.
+A default title is generated if
+.Ar title
+is not specified.
+.It Fl k , Fl Fl keep-going
+Add a
+.Dq keep on going
+option to
+.Ar build_command .
+Currently supports make and xcodebuild. This is a convenience option;
+one can specify this behavior directly using build options.
+.It Fl o
+Target directory for HTML report files. Subdirectories will be
+created as needed to represent separate invocations
+of the analyzer. If this option is not specified, a directory is
+created in /tmp (TMPDIR on Mac OS X) to store the reports.
+.It Fl plist
+Output the results as a set of
+.Li .plist
+files. (By default the output of
+.Nm
+is a set of HTML files.)
+.It Fl plist-html
+Output the results as a set of HTML and .plist files
+.It Fl Fl status-bugs
+Set exit status to 1 if it found potential bugs and 0 otherwise. By
+default the exit status of
+.Nm
+is that returned by
+.Ar build_command .
+.It Fl Fl use-c++ Ns Op = Ns Ar compiler_path
+Guess the default compiler for your C++ and Objective-C++ code. Use this
+option to specify an alternate compiler.
+.It Fl Fl use-cc Ns Op = Ns Ar compiler_path
+Guess the default compiler for your C and Objective-C code. Use this
+option to specify an alternate compiler.
+.It Fl v
+Verbose output from
+.Nm
+and the analyzer. A second and
+third
+.Ar v
+increases verbosity.
+.It Fl V , Fl Fl view
+View analysis results in a web browser when the build completes.
+.It Fl constraints Op Ar model
+Specify the contraint engine used by the analyzer. By default the
+.Ql range
+model is used. Specifying
+.Ql basic
+uses a simpler, less powerful constraint model used by checker-0.160
+and earlier.
+.It Fl maxloop Ar N
+Specifiy the number of times a block can be visited before giving
+up. Default is 4. Increase for more comprehensive coverage at a
+cost of speed.
+.It Fl no-failure-reports
+Do not create a
+.Ql failures
+subdirectory that includes analyzer crash reports and preprocessed
+source files.
+.It Fl stats
+Generates visitation statistics for the project being analyzed.
+.It Fl store Op Ar model
+Specify the store model used by the analyzer. By default, the
+.Ql region
+store model is used.
+.Ql region
+specifies a field-
+sensitive store model. Users can also specify
+.Ql basic
+which is far less precise but can more quickly analyze code.
+.Ql basic
+was the default store model for checker-0.221 and earlier.
+.\"
+.El
+.Sh RETURN VALUES
+.Nm
+returns the value returned by
+.Ar build_command
+unless
+.Fl Fl status-bugs
+or
+.Fl Fl keep-going
+is used.
+.\"
+.\" Other sections not yet used ...
+.\" .Sh ENVIRONMENT
+.\" .Sh FILES
+.\" .Sh DIAGNOSTICS
+.\" .Sh COMPATIBILITY
+.\" .Sh HISTORY
+.\" .Sh BUGS
+.\"
+.Sh CHECKERS
+The checkers listed below may be enabled/disabled using the
+.Fl enable-checker
+and
+.Fl disable-checker
+options.
+A default group of checkers is run unless explicitly disabled.
+Exactly which checkers constitute the default group is a function
+of the operating system in use; they are listed with
+.Fl Fl help-checkers .
+.Bl -tag -width indent.
+.It core.AdjustedReturnValue
+Check to see if the return value of a function call is different than
+the caller expects (e.g., from calls through function pointers).
+.It core.AttributeNonNull
+Check for null pointers passed as arguments to a function whose arguments are marked with the
+.Ql nonnull
+attribute.
+.It core.CallAndMessage
+Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers).
+.It core.DivideZero
+Check for division by zero.
+.It core.NullDereference
+Check for dereferences of null pointers.
+.It core.StackAddressEscape
+Check that addresses to stack memory do not escape the function.
+.It core.UndefinedBinaryOperatorResult
+Check for undefined results of binary operators.
+.It core.VLASize
+Check for declarations of VLA of undefined or zero size.
+.It core.builtin.BuiltinFunctions
+Evaluate compiler builtin functions, e.g.
+.Fn alloca .
+.It core.builtin.NoReturnFunctions
+Evaluate
+.Ql panic
+functions that are known to not return to the caller.
+.It core.uninitialized.ArraySubscript
+Check for uninitialized values used as array subscripts.
+.It core.uninitialized.Assign
+Check for assigning uninitialized values.
+.It core.uninitialized.Branch
+Check for uninitialized values used as branch conditions.
+.It core.uninitialized.CapturedBlockVariable
+Check for blocks that capture uninitialized values.
+.It core.uninitialized.UndefReturn
+Check for uninitialized values being returned to the caller.
+.It deadcode.DeadStores
+Check for values stored to variables that are never read afterwards.
+.It debug.DumpCFG
+Display Control-Flow Graphs.
+.It debug.DumpCallGraph
+Display Call Graph.
+.It debug.DumpDominators
+Print the dominance tree for a given Control-Flow Graph.
+.It debug.DumpLiveVars
+Print results of live variable analysis.
+.It debug.Stats
+Emit warnings with analyzer statistics.
+.It debug.TaintTest
+Mark tainted symbols as such.
+.It debug.ViewCFG
+View Control-Flow Graphs using
+.Ic GraphViz .
+.It debug.ViewCallGraph
+View Call Graph using
+.Ic GraphViz .
+.It llvm.Conventions
+Check code for LLVM codebase conventions.
+.It osx.API
+Check for proper uses of various Mac OS X APIs.
+.It osx.AtomicCAS
+Evaluate calls to
+.Vt OSAtomic
+functions.
+.It osx.SecKeychainAPI
+Check for proper uses of Secure Keychain APIs.
+.It osx.cocoa.AtSync
+Check for null pointers used as mutexes for @synchronized.
+.It osx.cocoa.ClassRelease
+Check for sending
+.Ql retain ,
+.Ql release,
+or
+.Ql autorelease
+directly to a Class.
+.It osx.cocoa.IncompatibleMethodTypes
+Warn about Objective-C method signatures with type incompatibilities.
+.It osx.cocoa.NSAutoreleasePool
+Warn for suboptimal uses of
+.Vt NSAutoreleasePool
+in Objective-C GC mode.
+.It osx.cocoa.NSError
+Check usage of NSError** parameters.
+.It osx.cocoa.NilArg
+Check for prohibited nil arguments to Objective-C method calls.
+.It osx.cocoa.RetainCount
+Check for leaks and improper reference count management.
+.It osx.cocoa.SelfInit
+Check that
+.Ql self
+is properly initialized inside an initializer method.
+.It osx.cocoa.UnusedIvars
+Warn about private ivars that are never used.
+.It osx.cocoa.VariadicMethodTypes
+Check for passing non-Objective-C types to variadic methods that expect only Objective-C types.
+.It osx.coreFoundation.CFError
+Check usage of CFErrorRef* parameters.
+.It osx.coreFoundation.CFNumber
+Check for proper uses of
+.Fn CFNumberCreate .
+.It osx.coreFoundation.CFRetainRelease
+Check for null arguments to
+.Fn CFRetain
+and
+.Fn CFRelease .
+.It osx.coreFoundation.containers.OutOfBounds
+Checks for index out-of-bounds when using the
+.Vt CFArray
+API.
+.It osx.coreFoundation.containers.PointerSizedValues
+Warns if
+.Vt CFArray ,
+.Vt CFDictionary ,
+or
+.Vt CFSet
+are created with non-pointer-size values.
+.It security.FloatLoopCounter
+Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP).
+.It security.insecureAPI.UncheckedReturn
+Warn on uses of functions whose return values must be always checked.
+.It security.insecureAPI.getpw
+Warn on uses of
+.Fn getpw .
+.It security.insecureAPI.gets
+Warn on uses of
+.Fn gets .
+.It security.insecureAPI.mkstemp
+Warn when
+.Fn mkstemp
+is passed fewer than 6 X's in the format string.
+.It security.insecureAPI.mktemp
+Warn on uses of
+.Fn mktemp .
+.It security.insecureAPI.rand
+Warn on uses of
+.Fn rand ,
+.Fn random ,
+and related functions.
+.It security.insecureAPI.strcpy
+Warn on uses of
+.Fn strcpy
+and
+.Fn strcat .
+.It security.insecureAPI.vfork
+Warn on uses of
+.Fn vfork .
+.It unix.API
+Check calls to various UNIX/Posix functions.
+.It unix.Malloc
+Check for memory leaks, double free, and use-after-free.
+.It unix.cstring.BadSizeArg
+Check the size argument passed into C string functions for common
+erroneous patterns.
+.It unix.cstring.NullArg
+Check for null pointers being passed as arguments to C string functions.
+.El
+.\"
+.Sh EXAMPLE
+.Ic scan-build -o /tmp/myhtmldir make -j4
+.Pp
+The above example causes analysis reports to be deposited into
+a subdirectory of
+.Pa /tmp/myhtmldir
+and to run
+.Ic make
+with the
+.Fl j4
+option.
+A different subdirectory is created each time
+.Nm
+analyzes a project.
+The analyzer should support most parallel builds, but not distributed builds.
+.Sh AUTHORS
+.Nm
+was written by
+.An "Ted Kremenek" .
+Documentation contributed by
+.An "James K. Lowden" Aq jklowden@schemamania.org .
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
index 06e1d85..c280bb4 100755
--- a/tools/scan-build/set-xcode-analyzer
+++ b/tools/scan-build/set-xcode-analyzer
@@ -75,7 +75,11 @@ def main():
print "(+) Using the Clang bundled with Xcode"
path = options.default
- xcode_path = subprocess.check_output(["xcode-select", "-print-path"])
+ try:
+ xcode_path = subprocess.check_output(["xcode-select", "-print-path"])
+ except AttributeError:
+ # Fall back to the default install location when using Python < 2.7.0
+ xcode_path = "/Developer"
if (re.search("Xcode.app", xcode_path)):
# Cut off the 'Developer' dir, as the xcspec lies in another part
# of the Xcode.app subtree.
OpenPOWER on IntegriCloud