Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit dd3e554

Browse files
committed
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130808 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent d808bd2 commit dd3e554

File tree

12 files changed

+88
-18
lines changed

12 files changed

+88
-18
lines changed

include/clang-c/Index.h

+8
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,14 @@ CINDEX_LINKAGE CXString clang_getFileName(CXFile SFile);
221221
*/
222222
CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile);
223223

224+
/**
225+
* \brief Determine whether the given header is guarded against
226+
* multiple inclusions, either with the conventional
227+
* #ifndef/#define/#endif macro guards or with #pragma once.
228+
*/
229+
CINDEX_LINKAGE unsigned
230+
clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file);
231+
224232
/**
225233
* \brief Retrieve a file handle within the given translation unit.
226234
*

include/clang/Lex/HeaderSearch.h

+17-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ struct HeaderFileInfo {
3131
/// isImport - True if this is a #import'd or #pragma once file.
3232
unsigned isImport : 1;
3333

34+
/// isPragmaOnce - True if this is #pragma once file.
35+
unsigned isPragmaOnce : 1;
36+
3437
/// DirInfo - Keep track of whether this is a system header, and if so,
3538
/// whether it is C++ clean or not. This can be set by the include paths or
3639
/// by #pragma gcc system_header. This is an instance of
@@ -66,8 +69,8 @@ struct HeaderFileInfo {
6669
const IdentifierInfo *ControllingMacro;
6770

6871
HeaderFileInfo()
69-
: isImport(false), DirInfo(SrcMgr::C_User), External(false),
70-
Resolved(false), NumIncludes(0), ControllingMacroID(0),
72+
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
73+
External(false), Resolved(false), NumIncludes(0), ControllingMacroID(0),
7174
ControllingMacro(0) {}
7275

7376
/// \brief Retrieve the controlling macro for this header file, if
@@ -77,7 +80,8 @@ struct HeaderFileInfo {
7780
/// \brief Determine whether this is a non-default header file info, e.g.,
7881
/// it corresponds to an actual header we've included or tried to include.
7982
bool isNonDefault() const {
80-
return isImport || NumIncludes || ControllingMacro || ControllingMacroID;
83+
return isImport || isPragmaOnce || NumIncludes || ControllingMacro ||
84+
ControllingMacroID;
8185
}
8286
};
8387

@@ -242,7 +246,9 @@ class HeaderSearch {
242246
/// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g.
243247
/// due to #pragma once.
244248
void MarkFileIncludeOnce(const FileEntry *File) {
245-
getFileInfo(File).isImport = true;
249+
HeaderFileInfo &FI = getFileInfo(File);
250+
FI.isImport = true;
251+
FI.isPragmaOnce = true;
246252
}
247253

248254
/// MarkFileSystemHeader - Mark the specified file as a system header, e.g.
@@ -265,6 +271,13 @@ class HeaderSearch {
265271
getFileInfo(File).ControllingMacro = ControllingMacro;
266272
}
267273

274+
/// \brief Determine whether this file is intended to be safe from
275+
/// multiple inclusions, e.g., it has #pragma once or a controlling
276+
/// macro.
277+
///
278+
/// This routine does not consider the effect of #import
279+
bool isFileMultipleIncludeGuarded(const FileEntry *File);
280+
268281
/// CreateHeaderMap - This method returns a HeaderMap for the specified
269282
/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
270283
const HeaderMap *CreateHeaderMap(const FileEntry *FE);

lib/Lex/HeaderSearch.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,21 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
482482
return HFI;
483483
}
484484

485+
bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
486+
// Check if we've ever seen this file as a header.
487+
if (File->getUID() >= FileInfo.size())
488+
return false;
489+
490+
// Resolve header file info from the external source, if needed.
491+
HeaderFileInfo &HFI = FileInfo[File->getUID()];
492+
if (ExternalSource && !HFI.Resolved) {
493+
HFI = ExternalSource->GetHeaderFileInfo(File);
494+
HFI.Resolved = true;
495+
}
496+
497+
return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID;
498+
}
499+
485500
void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
486501
if (UID >= FileInfo.size())
487502
FileInfo.resize(UID+1);

lib/Serialization/ASTReader.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1697,7 +1697,8 @@ namespace {
16971697
using namespace clang::io;
16981698
HeaderFileInfo HFI;
16991699
unsigned Flags = *d++;
1700-
HFI.isImport = (Flags >> 3) & 0x01;
1700+
HFI.isImport = (Flags >> 4) & 0x01;
1701+
HFI.isPragmaOnce = (Flags >> 3) & 0x01;
17011702
HFI.DirInfo = (Flags >> 1) & 0x03;
17021703
HFI.Resolved = Flags & 0x01;
17031704
HFI.NumIncludes = ReadUnalignedLE16(d);

lib/Serialization/ASTWriter.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1280,7 +1280,8 @@ namespace {
12801280
using namespace clang::io;
12811281
uint64_t Start = Out.tell(); (void)Start;
12821282

1283-
unsigned char Flags = (Data.isImport << 3)
1283+
unsigned char Flags = (Data.isImport << 4)
1284+
| (Data.isPragmaOnce << 3)
12841285
| (Data.DirInfo << 1)
12851286
| Data.Resolved;
12861287
Emit8(Out, (uint8_t)Flags);

test/Index/Inputs/guarded.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef GUARDED_HEADER_H
2+
#define GUARDED_HEADER_H
3+
4+
int y;
5+
6+
#endif // GUARDED_HEADER_H

test/Index/Inputs/pragma-once.h

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
int i;
3+

test/Index/annotate-tokens-pp.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ void test() {
2525
fun_with_macro_bodies(x, { int z = x; ++z; });
2626
}
2727

28-
// RUN: c-index-test -test-annotate-tokens=%s:2:1:26:1 -I%S/Inputs %s | FileCheck %s
28+
#include "pragma-once.h"
29+
#include "guarded.h"
30+
31+
// RUN: c-index-test -test-annotate-tokens=%s:2:1:30:1 -I%S/Inputs %s | FileCheck %s
2932
// CHECK: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
3033
// CHECK: Identifier: "define" [2:2 - 2:8] preprocessing directive=
3134
// CHECK: Identifier: "STILL_NOTHING" [2:9 - 2:22] macro definition=STILL_NOTHING
@@ -184,4 +187,5 @@ void test() {
184187
// CHECK: Punctuation: ")" [25:47 - 25:48] UnexposedStmt=
185188
// CHECK: Punctuation: ";" [25:48 - 25:49] UnexposedStmt=
186189
// CHECK: Punctuation: "}" [26:1 - 26:2] UnexposedStmt=
187-
190+
// CHECK: {{28:1.*inclusion directive=pragma-once.h.*multi-include guarded}}
191+
// CHECK: {{29:1.*inclusion directive=guarded.h.*multi-include guarded}}

tools/c-index-test/c-index-test.c

+16-10
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ int parse_remapped_files(int argc, const char **argv, int start_arg,
158158

159159
int want_display_name = 0;
160160

161-
static void PrintCursor(CXCursor Cursor) {
161+
static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
162162
if (clang_isInvalid(Cursor.kind)) {
163163
CXString ks = clang_getCursorKindSpelling(Cursor.kind);
164164
printf("Invalid Cursor => %s", clang_getCString(ks));
@@ -277,6 +277,9 @@ static void PrintCursor(CXCursor Cursor) {
277277
CXString Included = clang_getFileName(File);
278278
printf(" (%s)", clang_getCString(Included));
279279
clang_disposeString(Included);
280+
281+
if (clang_isFileMultipleIncludeGuarded(TU, File))
282+
printf(" [multi-include guarded]");
280283
}
281284
}
282285
}
@@ -426,7 +429,7 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
426429
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
427430
printf("// %s: %s:%d:%d: ", FileCheckPrefix,
428431
GetCursorSource(Cursor), line, column);
429-
PrintCursor(Cursor);
432+
PrintCursor(Data->TU, Cursor);
430433
PrintCursorExtent(Cursor);
431434
printf("\n");
432435
return CXChildVisit_Recurse;
@@ -479,7 +482,7 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
479482
} else if (Ref.kind != CXCursor_FunctionDecl) {
480483
printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
481484
curLine, curColumn);
482-
PrintCursor(Ref);
485+
PrintCursor(Data->TU, Ref);
483486
printf("\n");
484487
}
485488
}
@@ -554,6 +557,8 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
554557
CXClientData d) {
555558
const char *linkage = 0;
556559

560+
VisitorData *Data = (VisitorData *)d;
561+
557562
if (clang_isInvalid(clang_getCursorKind(cursor)))
558563
return CXChildVisit_Recurse;
559564

@@ -566,7 +571,7 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
566571
}
567572

568573
if (linkage) {
569-
PrintCursor(cursor);
574+
PrintCursor(Data->TU, cursor);
570575
printf("linkage=%s\n", linkage);
571576
}
572577

@@ -579,11 +584,12 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
579584

580585
static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
581586
CXClientData d) {
587+
VisitorData *Data = (VisitorData *)d;
582588

583589
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
584590
CXType T = clang_getCursorType(cursor);
585591
CXString S = clang_getTypeKindSpelling(T.kind);
586-
PrintCursor(cursor);
592+
PrintCursor(Data->TU, cursor);
587593
printf(" typekind=%s", clang_getCString(S));
588594
if (clang_isConstQualifiedType(T))
589595
printf(" const");
@@ -778,7 +784,7 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
778784
/* Logic for testing clang_getCursor(). */
779785
/******************************************************************************/
780786

781-
static void print_cursor_file_scan(CXCursor cursor,
787+
static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
782788
unsigned start_line, unsigned start_col,
783789
unsigned end_line, unsigned end_col,
784790
const char *prefix) {
@@ -787,7 +793,7 @@ static void print_cursor_file_scan(CXCursor cursor,
787793
printf("-%s", prefix);
788794
PrintExtent(stdout, start_line, start_col, end_line, end_col);
789795
printf(" ");
790-
PrintCursor(cursor);
796+
PrintCursor(TU, cursor);
791797
printf("\n");
792798
}
793799

@@ -832,7 +838,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
832838
cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
833839
if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
834840
prevCursor.kind != CXCursor_InvalidFile) {
835-
print_cursor_file_scan(prevCursor, start_line, start_col,
841+
print_cursor_file_scan(TU, prevCursor, start_line, start_col,
836842
line, col, prefix);
837843
start_line = line;
838844
start_col = col;
@@ -1183,7 +1189,7 @@ int inspect_cursor_at(int argc, const char **argv) {
11831189
clang_getLocation(TU, file, Locations[Loc].line,
11841190
Locations[Loc].column));
11851191
if (I + 1 == Repeats) {
1186-
PrintCursor(Cursor);
1192+
PrintCursor(TU, Cursor);
11871193
printf("\n");
11881194
free(Locations[Loc].filename);
11891195
}
@@ -1287,7 +1293,7 @@ int perform_token_annotation(int argc, const char **argv) {
12871293
PrintExtent(stdout, start_line, start_column, end_line, end_column);
12881294
if (!clang_isInvalid(cursors[i].kind)) {
12891295
printf(" ");
1290-
PrintCursor(cursors[i]);
1296+
PrintCursor(TU, cursors[i]);
12911297
}
12921298
printf("\n");
12931299
}

tools/libclang/CIndex.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "clang/Frontend/CompilerInstance.h"
3131
#include "clang/Frontend/FrontendDiagnostic.h"
3232
#include "clang/Lex/Lexer.h"
33+
#include "clang/Lex/HeaderSearch.h"
3334
#include "clang/Lex/PreprocessingRecord.h"
3435
#include "clang/Lex/Preprocessor.h"
3536
#include "llvm/ADT/STLExtras.h"
@@ -2890,6 +2891,16 @@ CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) {
28902891
return const_cast<FileEntry *>(FMgr.getFile(file_name));
28912892
}
28922893

2894+
unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file) {
2895+
if (!tu || !file)
2896+
return 0;
2897+
2898+
ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
2899+
FileEntry *FEnt = static_cast<FileEntry *>(file);
2900+
return CXXUnit->getPreprocessor().getHeaderSearchInfo()
2901+
.isFileMultipleIncludeGuarded(FEnt);
2902+
}
2903+
28932904
} // end: extern "C"
28942905

28952906
//===----------------------------------------------------------------------===//

tools/libclang/libclang.darwin.exports

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ _clang_isConstQualifiedType
115115
_clang_isCursorDefinition
116116
_clang_isDeclaration
117117
_clang_isExpression
118+
_clang_isFileMultipleIncludeGuarded
118119
_clang_isInvalid
119120
_clang_isPODType
120121
_clang_isPreprocessing

tools/libclang/libclang.exports

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ clang_isConstQualifiedType
115115
clang_isCursorDefinition
116116
clang_isDeclaration
117117
clang_isExpression
118+
clang_isFileMultipleIncludeGuarded
118119
clang_isInvalid
119120
clang_isPODType
120121
clang_isPreprocessing

0 commit comments

Comments
 (0)