#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken,
const MemoryBuffer &FromFile, StringRef EOL,
unsigned &NextToWrite, int &Lines);
+ bool HandleHasInclude(FileID FileId, Lexer &RawLex,
+ const DirectoryLookup *Lookup, Token &Tok,
+ bool &FileExists);
const FileChange *FindFileChangeLocation(SourceLocation Loc) const;
StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
};
return StringRef();
}
+// Expand __has_include and __has_include_next if possible. If there's no
+// definitive answer return false.
+bool InclusionRewriter::HandleHasInclude(
+ FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok,
+ bool &FileExists) {
+ // Lex the opening paren.
+ RawLex.LexFromRawLexer(Tok);
+ if (Tok.isNot(tok::l_paren))
+ return false;
+
+ RawLex.LexFromRawLexer(Tok);
+
+ SmallString<128> FilenameBuffer;
+ StringRef Filename;
+ // Since the raw lexer doesn't give us angle_literals we have to parse them
+ // ourselves.
+ // FIXME: What to do if the file name is a macro?
+ if (Tok.is(tok::less)) {
+ RawLex.LexFromRawLexer(Tok);
+
+ FilenameBuffer += '<';
+ do {
+ if (Tok.is(tok::eod)) // Sanity check.
+ return false;
+
+ if (Tok.is(tok::raw_identifier))
+ PP.LookUpIdentifierInfo(Tok);
+
+ // Get the string piece.
+ SmallVector<char, 128> TmpBuffer;
+ bool Invalid = false;
+ StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid);
+ if (Invalid)
+ return false;
+
+ FilenameBuffer += TmpName;
+
+ RawLex.LexFromRawLexer(Tok);
+ } while (Tok.isNot(tok::greater));
+
+ FilenameBuffer += '>';
+ Filename = FilenameBuffer;
+ } else {
+ if (Tok.isNot(tok::string_literal))
+ return false;
+
+ bool Invalid = false;
+ Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid);
+ if (Invalid)
+ return false;
+ }
+
+ // Lex the closing paren.
+ RawLex.LexFromRawLexer(Tok);
+ if (Tok.isNot(tok::r_paren))
+ return false;
+
+ // Now ask HeaderInfo if it knows about the header.
+ // FIXME: Subframeworks aren't handled here. Do we care?
+ bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
+ const DirectoryLookup *CurDir;
+ const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
+ Filename, isAngled, 0, CurDir,
+ PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false);
+
+ FileExists = File != 0;
+ return true;
+}
+
/// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it
/// and including content of included files recursively.
bool InclusionRewriter::Process(FileID FileId,
RawLex.LexFromRawLexer(RawToken);
if (RawToken.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawToken);
- if (RawToken.is(tok::identifier)) {
+ if (RawToken.is(tok::identifier) || RawToken.is(tok::kw_if)) {
switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_include_next:
}
break;
}
+ case tok::pp_if:
+ case tok::pp_elif:
+ // Rewrite special builtin macros to avoid pulling in host details.
+ do {
+ // Walk over the directive.
+ RawLex.LexFromRawLexer(RawToken);
+ if (RawToken.is(tok::raw_identifier))
+ PP.LookUpIdentifierInfo(RawToken);
+
+ if (RawToken.is(tok::identifier)) {
+ bool HasFile;
+ SourceLocation Loc = RawToken.getLocation();
+
+ // Rewrite __has_include(x)
+ if (RawToken.getIdentifierInfo()->isStr("__has_include")) {
+ if (!HandleHasInclude(FileId, RawLex, 0, RawToken, HasFile))
+ continue;
+ // Rewrite __has_include_next(x)
+ } else if (RawToken.getIdentifierInfo()->isStr(
+ "__has_include_next")) {
+ const DirectoryLookup *Lookup = PP.GetCurDirLookup();
+ if (Lookup)
+ ++Lookup;
+
+ if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken,
+ HasFile))
+ continue;
+ } else {
+ continue;
+ }
+ // Replace the macro with (0) or (1), followed by the commented
+ // out macro for reference.
+ OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc),
+ EOL, Line);
+ OS << '(' << (int) HasFile << ")/*";
+ OutputContentUpTo(FromFile, NextToWrite,
+ SM.getFileOffset(RawToken.getLocation()) +
+ RawToken.getLength(),
+ EOL, Line);
+ OS << "*/";
+ }
+ } while (RawToken.isNot(tok::eod));
+
+ break;
default:
break;
}
continues */
#include "rewrite-includes7.h"
#include "rewrite-includes7.h"
+#include "rewrite-includes8.h"
// ENDCOMPARE
// CHECK: {{^}}// STARTCOMPARE{{$}}
// CHECK-NEXT: {{^}}#define A(a,b) a ## b{{$}}
// CHECK-NEXT: {{^}}#include "rewrite-includes7.h"{{$}}
// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
// CHECK-NEXT: {{^}}# 21 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes8.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes8.h" 1{{$}}
+// CHECK-NEXT: {{^}}#if (1)/*__has_include_next(<rewrite-includes8.h>)*/{{$}}
+// CHECK-NEXT: {{^}}#elif (0)/*__has_include(<rewrite-includes8.hfail>)*/{{$}}
+// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}#if !(1)/*__has_include("rewrite-includes8.h")*/{{$}}
+// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}# 22 "{{.*}}rewrite-includes.c" 2{{$}}
// CHECK-NEXT: {{^}}// ENDCOMPARE{{$}}
// CHECKNL: {{^}}// STARTCOMPARE{{$}}
// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
// CHECKNL-NEXT: {{^}}#include "rewrite-includes7.h"{{$}}
// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECKNL-NEXT: {{^}}#include "rewrite-includes8.h"{{$}}
+// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECKNL-NEXT: {{^}}#if (1)/*__has_include_next(<rewrite-includes8.h>)*/{{$}}
+// CHECKNL-NEXT: {{^}}#elif (0)/*__has_include(<rewrite-includes8.hfail>)*/{{$}}
+// CHECKNL-NEXT: {{^}}#endif{{$}}
+// CHECKNL-NEXT: {{^}}#if !(1)/*__has_include("rewrite-includes8.h")*/{{$}}
+// CHECKNL-NEXT: {{^}}#endif{{$}}
// CHECKNL-NEXT: {{^}}// ENDCOMPARE{{$}}