зеркало из https://github.com/microsoft/clang-1.git
Introduce a new lexer function to compute the "preamble" of a file,
which is the part of the file that contains all of the initial comments, includes, and preprocessor directives that occur before any of the actual code. Added a new -print-preamble cc1 action that is only used for testing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108913 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
4751a53c5e
Коммит
f033f1da4a
|
@ -304,6 +304,9 @@ def fixit_EQ : Joined<"-fixit=">,
|
||||||
HelpText<"Apply fix-it advice creating a file with the given suffix">;
|
HelpText<"Apply fix-it advice creating a file with the given suffix">;
|
||||||
def parse_print_callbacks : Flag<"-parse-print-callbacks">,
|
def parse_print_callbacks : Flag<"-parse-print-callbacks">,
|
||||||
HelpText<"Run parser and print each callback invoked">;
|
HelpText<"Run parser and print each callback invoked">;
|
||||||
|
def print_preamble : Flag<"-print-preamble">,
|
||||||
|
HelpText<"Print the \"preamble\" of a file, which is a candidate for implicit"
|
||||||
|
" precompiled headers.">;
|
||||||
def emit_html : Flag<"-emit-html">,
|
def emit_html : Flag<"-emit-html">,
|
||||||
HelpText<"Output input source as HTML">;
|
HelpText<"Output input source as HTML">;
|
||||||
def ast_print : Flag<"-ast-print">,
|
def ast_print : Flag<"-ast-print">,
|
||||||
|
|
|
@ -134,6 +134,16 @@ public:
|
||||||
virtual bool hasCodeCompletionSupport() const;
|
virtual bool hasCodeCompletionSupport() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PrintPreambleAction : public FrontendAction {
|
||||||
|
protected:
|
||||||
|
void ExecuteAction();
|
||||||
|
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &, llvm::StringRef) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool usesPreprocessorOnly() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Preprocessor Actions
|
// Preprocessor Actions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -174,7 +184,7 @@ protected:
|
||||||
|
|
||||||
virtual bool hasPCHSupport() const { return true; }
|
virtual bool hasPCHSupport() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace frontend {
|
||||||
ParseSyntaxOnly, ///< Parse and perform semantic analysis.
|
ParseSyntaxOnly, ///< Parse and perform semantic analysis.
|
||||||
PluginAction, ///< Run a plugin action, \see ActionName.
|
PluginAction, ///< Run a plugin action, \see ActionName.
|
||||||
PrintDeclContext, ///< Print DeclContext and their Decls.
|
PrintDeclContext, ///< Print DeclContext and their Decls.
|
||||||
|
PrintPreamble, ///< Print the "preamble" of the input file
|
||||||
PrintPreprocessedInput, ///< -E mode.
|
PrintPreprocessedInput, ///< -E mode.
|
||||||
RewriteMacros, ///< Expand macros but not #includes.
|
RewriteMacros, ///< Expand macros but not #includes.
|
||||||
RewriteObjC, ///< ObjC->C Rewriter.
|
RewriteObjC, ///< ObjC->C Rewriter.
|
||||||
|
|
|
@ -219,6 +219,19 @@ public:
|
||||||
const SourceManager &SM,
|
const SourceManager &SM,
|
||||||
const LangOptions &LangOpts);
|
const LangOptions &LangOpts);
|
||||||
|
|
||||||
|
/// \brief Compute the preamble of the given file.
|
||||||
|
///
|
||||||
|
/// The preamble of a file contains the initial comments, include directives,
|
||||||
|
/// and other preprocessor directives that occur before the code in this
|
||||||
|
/// particular file actually begins. The preamble of the main source file is
|
||||||
|
/// a potential prefix header.
|
||||||
|
///
|
||||||
|
/// \param Buffer The memory buffer containing the file's contents.
|
||||||
|
///
|
||||||
|
/// \returns The offset into the file where the preamble ends and the rest
|
||||||
|
/// of the file begins.
|
||||||
|
static unsigned ComputePreamble(const llvm::MemoryBuffer *Buffer);
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Internal implementation interfaces.
|
// Internal implementation interfaces.
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -331,6 +331,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
|
||||||
case frontend::ParsePrintCallbacks: return "-parse-print-callbacks";
|
case frontend::ParsePrintCallbacks: return "-parse-print-callbacks";
|
||||||
case frontend::ParseSyntaxOnly: return "-fsyntax-only";
|
case frontend::ParseSyntaxOnly: return "-fsyntax-only";
|
||||||
case frontend::PrintDeclContext: return "-print-decl-contexts";
|
case frontend::PrintDeclContext: return "-print-decl-contexts";
|
||||||
|
case frontend::PrintPreamble: return "-print-preamble";
|
||||||
case frontend::PrintPreprocessedInput: return "-E";
|
case frontend::PrintPreprocessedInput: return "-E";
|
||||||
case frontend::RewriteMacros: return "-rewrite-macros";
|
case frontend::RewriteMacros: return "-rewrite-macros";
|
||||||
case frontend::RewriteObjC: return "-rewrite-objc";
|
case frontend::RewriteObjC: return "-rewrite-objc";
|
||||||
|
@ -989,6 +990,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
||||||
Opts.ProgramAction = frontend::ParseSyntaxOnly; break;
|
Opts.ProgramAction = frontend::ParseSyntaxOnly; break;
|
||||||
case OPT_print_decl_contexts:
|
case OPT_print_decl_contexts:
|
||||||
Opts.ProgramAction = frontend::PrintDeclContext; break;
|
Opts.ProgramAction = frontend::PrintDeclContext; break;
|
||||||
|
case OPT_print_preamble:
|
||||||
|
Opts.ProgramAction = frontend::PrintPreamble; break;
|
||||||
case OPT_E:
|
case OPT_E:
|
||||||
Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
|
Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
|
||||||
case OPT_rewrite_macros:
|
case OPT_rewrite_macros:
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||||
#include "clang/Frontend/Utils.h"
|
#include "clang/Frontend/Utils.h"
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
|
@ -192,3 +193,32 @@ void PrintPreprocessedAction::ExecuteAction() {
|
||||||
DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
|
DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
|
||||||
CI.getPreprocessorOutputOpts());
|
CI.getPreprocessorOutputOpts());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrintPreambleAction::ExecuteAction() {
|
||||||
|
switch (getCurrentFileKind()) {
|
||||||
|
case IK_C:
|
||||||
|
case IK_CXX:
|
||||||
|
case IK_ObjC:
|
||||||
|
case IK_ObjCXX:
|
||||||
|
case IK_OpenCL:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IK_None:
|
||||||
|
case IK_Asm:
|
||||||
|
case IK_PreprocessedC:
|
||||||
|
case IK_PreprocessedCXX:
|
||||||
|
case IK_PreprocessedObjC:
|
||||||
|
case IK_PreprocessedObjCXX:
|
||||||
|
case IK_AST:
|
||||||
|
case IK_LLVM_IR:
|
||||||
|
// We can't do anything with these.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getFile(getCurrentFile());
|
||||||
|
if (Buffer) {
|
||||||
|
unsigned Preamble = Lexer::ComputePreamble(Buffer);
|
||||||
|
llvm::outs().write(Buffer->getBufferStart(), Preamble);
|
||||||
|
delete Buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "clang/Lex/Preprocessor.h"
|
#include "clang/Lex/Preprocessor.h"
|
||||||
#include "clang/Lex/LexDiagnostic.h"
|
#include "clang/Lex/LexDiagnostic.h"
|
||||||
#include "clang/Basic/SourceManager.h"
|
#include "clang/Basic/SourceManager.h"
|
||||||
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
@ -247,6 +248,130 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
|
||||||
return TheTok.getLength();
|
return TheTok.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
enum PreambleDirectiveKind {
|
||||||
|
PDK_Skipped,
|
||||||
|
PDK_StartIf,
|
||||||
|
PDK_EndIf,
|
||||||
|
PDK_Unknown
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer) {
|
||||||
|
// Create a lexer starting at the beginning of the file. Note that we use a
|
||||||
|
// "fake" file source location at offset 1 so that the lexer will track our
|
||||||
|
// position within the file.
|
||||||
|
const unsigned StartOffset = 1;
|
||||||
|
SourceLocation StartLoc = SourceLocation::getFromRawEncoding(StartOffset);
|
||||||
|
LangOptions LangOpts;
|
||||||
|
Lexer TheLexer(StartLoc, LangOpts, Buffer->getBufferStart(),
|
||||||
|
Buffer->getBufferStart(), Buffer->getBufferEnd());
|
||||||
|
|
||||||
|
bool InPreprocessorDirective = false;
|
||||||
|
Token TheTok;
|
||||||
|
Token IfStartTok;
|
||||||
|
unsigned IfCount = 0;
|
||||||
|
do {
|
||||||
|
TheLexer.LexFromRawLexer(TheTok);
|
||||||
|
|
||||||
|
if (InPreprocessorDirective) {
|
||||||
|
// If we've hit the end of the file, we're done.
|
||||||
|
if (TheTok.getKind() == tok::eof) {
|
||||||
|
InPreprocessorDirective = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven't hit the end of the preprocessor directive, skip this
|
||||||
|
// token.
|
||||||
|
if (!TheTok.isAtStartOfLine())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// We've passed the end of the preprocessor directive, and will look
|
||||||
|
// at this token again below.
|
||||||
|
InPreprocessorDirective = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comments are okay; skip over them.
|
||||||
|
if (TheTok.getKind() == tok::comment)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TheTok.isAtStartOfLine() && TheTok.getKind() == tok::hash) {
|
||||||
|
// This is the start of a preprocessor directive.
|
||||||
|
Token HashTok = TheTok;
|
||||||
|
InPreprocessorDirective = true;
|
||||||
|
|
||||||
|
// Figure out which direective this is. Since we're lexing raw tokens,
|
||||||
|
// we don't have an identifier table available. Instead, just look at
|
||||||
|
// the raw identifier to recognize and categorize preprocessor directives.
|
||||||
|
TheLexer.LexFromRawLexer(TheTok);
|
||||||
|
if (TheTok.getKind() == tok::identifier && !TheTok.needsCleaning()) {
|
||||||
|
const char *IdStart = Buffer->getBufferStart()
|
||||||
|
+ TheTok.getLocation().getRawEncoding() - 1;
|
||||||
|
llvm::StringRef Keyword(IdStart, TheTok.getLength());
|
||||||
|
PreambleDirectiveKind PDK
|
||||||
|
= llvm::StringSwitch<PreambleDirectiveKind>(Keyword)
|
||||||
|
.Case("include", PDK_Skipped)
|
||||||
|
.Case("__include_macros", PDK_Skipped)
|
||||||
|
.Case("define", PDK_Skipped)
|
||||||
|
.Case("undef", PDK_Skipped)
|
||||||
|
.Case("line", PDK_Skipped)
|
||||||
|
.Case("error", PDK_Skipped)
|
||||||
|
.Case("pragma", PDK_Skipped)
|
||||||
|
.Case("import", PDK_Skipped)
|
||||||
|
.Case("include_next", PDK_Skipped)
|
||||||
|
.Case("warning", PDK_Skipped)
|
||||||
|
.Case("ident", PDK_Skipped)
|
||||||
|
.Case("sccs", PDK_Skipped)
|
||||||
|
.Case("assert", PDK_Skipped)
|
||||||
|
.Case("unassert", PDK_Skipped)
|
||||||
|
.Case("if", PDK_StartIf)
|
||||||
|
.Case("ifdef", PDK_StartIf)
|
||||||
|
.Case("ifndef", PDK_StartIf)
|
||||||
|
.Case("elif", PDK_Skipped)
|
||||||
|
.Case("else", PDK_Skipped)
|
||||||
|
.Case("endif", PDK_EndIf)
|
||||||
|
.Default(PDK_Unknown);
|
||||||
|
|
||||||
|
switch (PDK) {
|
||||||
|
case PDK_Skipped:
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case PDK_StartIf:
|
||||||
|
if (IfCount == 0)
|
||||||
|
IfStartTok = HashTok;
|
||||||
|
|
||||||
|
++IfCount;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case PDK_EndIf:
|
||||||
|
// Mismatched #endif. The preamble ends here.
|
||||||
|
if (IfCount == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
--IfCount;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case PDK_Unknown:
|
||||||
|
// We don't know what this directive is; stop at the '#'.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only end up here if we didn't recognize the preprocessor
|
||||||
|
// directive or it was one that can't occur in the preamble at this
|
||||||
|
// point. Roll back the current token to the location of the '#'.
|
||||||
|
InPreprocessorDirective = false;
|
||||||
|
TheTok = HashTok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We hit a token
|
||||||
|
break;
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
SourceLocation End = IfCount? IfStartTok.getLocation() : TheTok.getLocation();
|
||||||
|
return End.getRawEncoding() - StartLoc.getRawEncoding();
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Character information.
|
// Character information.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Preamble detection test: see below for comments and test commands.
|
||||||
|
|
||||||
|
#include <blah>
|
||||||
|
#ifndef FOO
|
||||||
|
#else
|
||||||
|
#ifdef BAR
|
||||||
|
#elif WIBBLE
|
||||||
|
#endif
|
||||||
|
#pragma unknown
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Preamble detection test: see below for comments and test commands.
|
||||||
|
|
||||||
|
#include <blah>
|
||||||
|
#ifndef FOO
|
||||||
|
#else
|
||||||
|
#ifdef BAR
|
||||||
|
#elif WIBBLE
|
||||||
|
#endif
|
||||||
|
#pragma unknown
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIBBLE
|
||||||
|
#include "honk"
|
||||||
|
#else
|
||||||
|
int foo();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This test checks for detection of the preamble of a file, which
|
||||||
|
// includes all of the starting comments and #includes. Note that any
|
||||||
|
// changes to the preamble part of this file must be mirrored in
|
||||||
|
// Inputs/preamble.txt, since we diff against it.
|
||||||
|
|
||||||
|
// RUN: %clang_cc1 -print-preamble %s > %t
|
||||||
|
// RUN: diff %t %S/Inputs/preamble.txt
|
||||||
|
|
|
@ -102,6 +102,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case PrintDeclContext: return new DeclContextPrintAction();
|
case PrintDeclContext: return new DeclContextPrintAction();
|
||||||
|
case PrintPreamble: return new PrintPreambleAction();
|
||||||
case PrintPreprocessedInput: return new PrintPreprocessedAction();
|
case PrintPreprocessedInput: return new PrintPreprocessedAction();
|
||||||
case RewriteMacros: return new RewriteMacrosAction();
|
case RewriteMacros: return new RewriteMacrosAction();
|
||||||
case RewriteObjC: return new RewriteObjCAction();
|
case RewriteObjC: return new RewriteObjCAction();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче