]> granicus.if.org Git - clang/commitdiff
Introduce a new libclang API, clang_isFileMultipleIncludeGuarded(),
authorDouglas Gregor <dgregor@apple.com>
Wed, 4 May 2011 00:14:37 +0000 (00:14 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 4 May 2011 00:14:37 +0000 (00:14 +0000)
which determines whether a particular file is actually a header that
is intended to be guarded from multiple inclusions within the same
translation unit.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130808 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/clang-c/Index.h
include/clang/Lex/HeaderSearch.h
lib/Lex/HeaderSearch.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Index/Inputs/guarded.h [new file with mode: 0644]
test/Index/Inputs/pragma-once.h [new file with mode: 0644]
test/Index/annotate-tokens-pp.c
tools/c-index-test/c-index-test.c
tools/libclang/CIndex.cpp
tools/libclang/libclang.darwin.exports
tools/libclang/libclang.exports

index d89a903e4112172f47277b53f3fbd7898949a981..2f2876e0fae1eb1079b8d033d6eb315e45f8f391 100644 (file)
@@ -221,6 +221,14 @@ CINDEX_LINKAGE CXString clang_getFileName(CXFile SFile);
  */
 CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile);
 
+/**
+ * \brief Determine whether the given header is guarded against
+ * multiple inclusions, either with the conventional
+ * #ifndef/#define/#endif macro guards or with #pragma once.
+ */
+CINDEX_LINKAGE unsigned 
+clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file);
+
 /**
  * \brief Retrieve a file handle within the given translation unit.
  *
index fec4dad1e73bbbd58034004e69974897c870a0ab..3d99f15412aaa3766c7d90cb25e24b6eae5b0533 100644 (file)
@@ -31,6 +31,9 @@ struct HeaderFileInfo {
   /// isImport - True if this is a #import'd or #pragma once file.
   unsigned isImport : 1;
 
+  /// isPragmaOnce - True if this is  #pragma once file.
+  unsigned isPragmaOnce : 1;
+
   /// DirInfo - Keep track of whether this is a system header, and if so,
   /// whether it is C++ clean or not.  This can be set by the include paths or
   /// by #pragma gcc system_header.  This is an instance of
@@ -66,8 +69,8 @@ struct HeaderFileInfo {
   const IdentifierInfo *ControllingMacro;
 
   HeaderFileInfo()
-    : isImport(false), DirInfo(SrcMgr::C_User), External(false), 
-      Resolved(false), NumIncludes(0), ControllingMacroID(0), 
+    : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), 
+      External(false), Resolved(false), NumIncludes(0), ControllingMacroID(0), 
       ControllingMacro(0)  {}
 
   /// \brief Retrieve the controlling macro for this header file, if
@@ -77,7 +80,8 @@ struct HeaderFileInfo {
   /// \brief Determine whether this is a non-default header file info, e.g.,
   /// it corresponds to an actual header we've included or tried to include.
   bool isNonDefault() const {
-    return isImport || NumIncludes || ControllingMacro || ControllingMacroID;
+    return isImport || isPragmaOnce || NumIncludes || ControllingMacro || 
+      ControllingMacroID;
   }
 };
 
@@ -242,7 +246,9 @@ public:
   /// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g.
   /// due to #pragma once.
   void MarkFileIncludeOnce(const FileEntry *File) {
-    getFileInfo(File).isImport = true;
+    HeaderFileInfo &FI = getFileInfo(File);
+    FI.isImport = true;
+    FI.isPragmaOnce = true;
   }
 
   /// MarkFileSystemHeader - Mark the specified file as a system header, e.g.
@@ -265,6 +271,13 @@ public:
     getFileInfo(File).ControllingMacro = ControllingMacro;
   }
 
+  /// \brief Determine whether this file is intended to be safe from
+  /// multiple inclusions, e.g., it has #pragma once or a controlling
+  /// macro.
+  ///
+  /// This routine does not consider the effect of #import 
+  bool isFileMultipleIncludeGuarded(const FileEntry *File);
+
   /// CreateHeaderMap - This method returns a HeaderMap for the specified
   /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
   const HeaderMap *CreateHeaderMap(const FileEntry *FE);
index 372078c60d20a514f974aff1192f81ad8767f374..b3301164bd29640b04d95b3b1d150f396342d4a0 100644 (file)
@@ -482,6 +482,21 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
   return HFI;
 }
 
+bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
+  // Check if we've ever seen this file as a header.
+  if (File->getUID() >= FileInfo.size())
+    return false;
+
+  // Resolve header file info from the external source, if needed.
+  HeaderFileInfo &HFI = FileInfo[File->getUID()];
+  if (ExternalSource && !HFI.Resolved) {
+    HFI = ExternalSource->GetHeaderFileInfo(File);
+    HFI.Resolved = true;
+  }
+
+  return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID;
+}
+
 void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
   if (UID >= FileInfo.size())
     FileInfo.resize(UID+1);
index d2e41a96c9461a33b7905bfcbdc93b2c1cfac34c..5a4c59e3cde247e1fd82367a52159ef4be694141 100644 (file)
@@ -1697,7 +1697,8 @@ namespace {
       using namespace clang::io;
       HeaderFileInfo HFI;
       unsigned Flags = *d++;
-      HFI.isImport = (Flags >> 3) & 0x01;
+      HFI.isImport = (Flags >> 4) & 0x01;
+      HFI.isPragmaOnce = (Flags >> 3) & 0x01;
       HFI.DirInfo = (Flags >> 1) & 0x03;
       HFI.Resolved = Flags & 0x01;
       HFI.NumIncludes = ReadUnalignedLE16(d);
index 6d44fb63e5a267ce4452b14c34d5b94080a7fef8..e711351add48818ab82f8b1c55ea1314712f29ce 100644 (file)
@@ -1280,7 +1280,8 @@ namespace {
       using namespace clang::io;
       uint64_t Start = Out.tell(); (void)Start;
       
-      unsigned char Flags = (Data.isImport << 3)
+      unsigned char Flags = (Data.isImport << 4)
+                          | (Data.isPragmaOnce << 3)
                           | (Data.DirInfo << 1)
                           | Data.Resolved;
       Emit8(Out, (uint8_t)Flags);
diff --git a/test/Index/Inputs/guarded.h b/test/Index/Inputs/guarded.h
new file mode 100644 (file)
index 0000000..0a1a6ac
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef GUARDED_HEADER_H
+#define GUARDED_HEADER_H
+
+int y;
+
+#endif // GUARDED_HEADER_H
diff --git a/test/Index/Inputs/pragma-once.h b/test/Index/Inputs/pragma-once.h
new file mode 100644 (file)
index 0000000..503cb3f
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+int i;
+
index 3dd9ffeddcbeeed3a15a108e768855a663d39322..01a615f0e4cbe709d4cb0bc0f8ee03fc631836c3 100644 (file)
@@ -25,7 +25,10 @@ void test() {
   fun_with_macro_bodies(x, { int z = x; ++z; });
 }
 
-// RUN: c-index-test -test-annotate-tokens=%s:2:1:26:1 -I%S/Inputs %s | FileCheck %s
+#include "pragma-once.h"
+#include "guarded.h"
+
+// RUN: c-index-test -test-annotate-tokens=%s:2:1:30:1 -I%S/Inputs %s | FileCheck %s
 // CHECK: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
 // CHECK: Identifier: "define" [2:2 - 2:8] preprocessing directive=
 // CHECK: Identifier: "STILL_NOTHING" [2:9 - 2:22] macro definition=STILL_NOTHING
@@ -184,4 +187,5 @@ void test() {
 // CHECK: Punctuation: ")" [25:47 - 25:48] UnexposedStmt=
 // CHECK: Punctuation: ";" [25:48 - 25:49] UnexposedStmt=
 // CHECK: Punctuation: "}" [26:1 - 26:2] UnexposedStmt=
-
+// CHECK: {{28:1.*inclusion directive=pragma-once.h.*multi-include guarded}}
+// CHECK: {{29:1.*inclusion directive=guarded.h.*multi-include guarded}}
index f7b7a367cfd6841bc6f8b1eaf59591274c88777e..e43ac0699f2e675b2208b00139ef5392bb7197cf 100644 (file)
@@ -158,7 +158,7 @@ int parse_remapped_files(int argc, const char **argv, int start_arg,
 
 int want_display_name = 0;
 
-static void PrintCursor(CXCursor Cursor) {
+static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
   if (clang_isInvalid(Cursor.kind)) {
     CXString ks = clang_getCursorKindSpelling(Cursor.kind);
     printf("Invalid Cursor => %s", clang_getCString(ks));
@@ -277,6 +277,9 @@ static void PrintCursor(CXCursor Cursor) {
       CXString Included = clang_getFileName(File);
       printf(" (%s)", clang_getCString(Included));
       clang_disposeString(Included);
+      
+      if (clang_isFileMultipleIncludeGuarded(TU, File))
+        printf("  [multi-include guarded]");
     }
   }
 }
@@ -426,7 +429,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(Data->TU, Cursor);
     PrintCursorExtent(Cursor);
     printf("\n");
     return CXChildVisit_Recurse;
@@ -479,7 +482,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(Data->TU, Ref);
         printf("\n");
       }
     }
@@ -554,6 +557,8 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
                                             CXClientData d) {
   const char *linkage = 0;
 
+  VisitorData *Data = (VisitorData *)d;
+
   if (clang_isInvalid(clang_getCursorKind(cursor)))
     return CXChildVisit_Recurse;
 
@@ -566,7 +571,7 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
   }
 
   if (linkage) {
-    PrintCursor(cursor);
+    PrintCursor(Data->TU, cursor);
     printf("linkage=%s\n", linkage);
   }
 
@@ -579,11 +584,12 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
 
 static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
                                              CXClientData d) {
+  VisitorData *Data = (VisitorData *)d;
 
   if (!clang_isInvalid(clang_getCursorKind(cursor))) {
     CXType T = clang_getCursorType(cursor);
     CXString S = clang_getTypeKindSpelling(T.kind);
-    PrintCursor(cursor);
+    PrintCursor(Data->TU, cursor);
     printf(" typekind=%s", clang_getCString(S));
     if (clang_isConstQualifiedType(T))
       printf(" const");
@@ -778,7 +784,7 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
 /* Logic for testing clang_getCursor().                                       */
 /******************************************************************************/
 
-static void print_cursor_file_scan(CXCursor cursor,
+static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
                                    unsigned start_line, unsigned start_col,
                                    unsigned end_line, unsigned end_col,
                                    const char *prefix) {
@@ -787,7 +793,7 @@ static void print_cursor_file_scan(CXCursor cursor,
     printf("-%s", prefix);
   PrintExtent(stdout, start_line, start_col, end_line, end_col);
   printf(" ");
-  PrintCursor(cursor);
+  PrintCursor(TU, cursor);
   printf("\n");
 }
 
@@ -832,7 +838,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
     cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
     if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
         prevCursor.kind != CXCursor_InvalidFile) {
-      print_cursor_file_scan(prevCursor, start_line, start_col,
+      print_cursor_file_scan(TU, prevCursor, start_line, start_col,
                              line, col, prefix);
       start_line = line;
       start_col = col;
@@ -1183,7 +1189,7 @@ int inspect_cursor_at(int argc, const char **argv) {
                                clang_getLocation(TU, file, Locations[Loc].line,
                                                  Locations[Loc].column));
       if (I + 1 == Repeats) {
-        PrintCursor(Cursor);
+        PrintCursor(TU, Cursor);
         printf("\n");
         free(Locations[Loc].filename);
       }
@@ -1287,7 +1293,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(TU, cursors[i]);
     }
     printf("\n");
   }
index 28f1506988e1498539dc7aaeecba8c2132d2cb02..e6774dc895cfa75f2b190af24d350fb0a31ab1ab 100644 (file)
@@ -30,6 +30,7 @@
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Lex/Lexer.h"
+#include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/STLExtras.h"
@@ -2890,6 +2891,16 @@ CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) {
   return const_cast<FileEntry *>(FMgr.getFile(file_name));
 }
 
+unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file) {
+  if (!tu || !file)
+    return 0;
+
+  ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+  FileEntry *FEnt = static_cast<FileEntry *>(file);
+  return CXXUnit->getPreprocessor().getHeaderSearchInfo()
+                                          .isFileMultipleIncludeGuarded(FEnt);
+}
+
 } // end: extern "C"
 
 //===----------------------------------------------------------------------===//
index 30c3fd1ac30a92fca90af3f5ef4535e994e1d3df..7bba6739c56fc532f8ffda53d60e206072eaf833 100644 (file)
@@ -115,6 +115,7 @@ _clang_isConstQualifiedType
 _clang_isCursorDefinition
 _clang_isDeclaration
 _clang_isExpression
+_clang_isFileMultipleIncludeGuarded
 _clang_isInvalid
 _clang_isPODType
 _clang_isPreprocessing
index 4e96e8a0d6d702ee60715a70335958d71d973a13..5f2c362f5b7e3fee312854af2037e338566a6fa1 100644 (file)
@@ -115,6 +115,7 @@ clang_isConstQualifiedType
 clang_isCursorDefinition
 clang_isDeclaration
 clang_isExpression
+clang_isFileMultipleIncludeGuarded
 clang_isInvalid
 clang_isPODType
 clang_isPreprocessing