Introduce a new libclang API, clang_isFileMultipleIncludeGuarded(),

which determines whether a particular file is actually a header that
is intended to be guarded from multiple inclusions within the same
translation unit.

llvm-svn: 130808
This commit is contained in:
Douglas Gregor 2011-05-04 00:14:37 +00:00
parent 24f3490467
commit 37aa4938c8
12 changed files with 88 additions and 18 deletions

View 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.
*

View 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);

View 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);

View 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);

View 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);

View File

@ -0,0 +1,6 @@
#ifndef GUARDED_HEADER_H
#define GUARDED_HEADER_H
int y;
#endif // GUARDED_HEADER_H

View File

@ -0,0 +1,3 @@
#pragma once
int i;

View 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}}

View 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");
}

View 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"
//===----------------------------------------------------------------------===//

View File

@ -115,6 +115,7 @@ _clang_isConstQualifiedType
_clang_isCursorDefinition
_clang_isDeclaration
_clang_isExpression
_clang_isFileMultipleIncludeGuarded
_clang_isInvalid
_clang_isPODType
_clang_isPreprocessing

View File

@ -115,6 +115,7 @@ clang_isConstQualifiedType
clang_isCursorDefinition
clang_isDeclaration
clang_isExpression
clang_isFileMultipleIncludeGuarded
clang_isInvalid
clang_isPODType
clang_isPreprocessing