forked from OSchip/llvm-project
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:
parent
24f3490467
commit
37aa4938c8
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef GUARDED_HEADER_H
|
||||
#define GUARDED_HEADER_H
|
||||
|
||||
int y;
|
||||
|
||||
#endif // GUARDED_HEADER_H
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
int i;
|
||||
|
|
@ -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}}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -115,6 +115,7 @@ _clang_isConstQualifiedType
|
|||
_clang_isCursorDefinition
|
||||
_clang_isDeclaration
|
||||
_clang_isExpression
|
||||
_clang_isFileMultipleIncludeGuarded
|
||||
_clang_isInvalid
|
||||
_clang_isPODType
|
||||
_clang_isPreprocessing
|
||||
|
|
|
@ -115,6 +115,7 @@ clang_isConstQualifiedType
|
|||
clang_isCursorDefinition
|
||||
clang_isDeclaration
|
||||
clang_isExpression
|
||||
clang_isFileMultipleIncludeGuarded
|
||||
clang_isInvalid
|
||||
clang_isPODType
|
||||
clang_isPreprocessing
|
||||
|
|
Loading…
Reference in New Issue