diff options
author | Eric Liu <ioeric@google.com> | 2019-01-29 14:40:01 +0000 |
---|---|---|
committer | Eric Liu <ioeric@google.com> | 2019-01-29 14:40:01 +0000 |
commit | a66f02343baeb83b5a08cc521e0a01793a38df64 (patch) | |
tree | 3e4e3641b71487c449d45b68c77f5be0745b99dd /lib/Tooling/Inclusions/HeaderIncludes.cpp | |
parent | 248e5bf6ef4ecf292928b99bf755b26b6ebd3c6f (diff) | |
download | clang-a66f02343baeb83b5a08cc521e0a01793a38df64.tar.gz |
[Tooling] Handle #pragma once header guard in include insertion.
Reviewers: ilya-biryukov
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D57223
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@352503 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Tooling/Inclusions/HeaderIncludes.cpp')
-rw-r--r-- | lib/Tooling/Inclusions/HeaderIncludes.cpp | 62 |
1 files changed, 44 insertions, 18 deletions
diff --git a/lib/Tooling/Inclusions/HeaderIncludes.cpp b/lib/Tooling/Inclusions/HeaderIncludes.cpp index 893b2e3bc5..a7f79c33bc 100644 --- a/lib/Tooling/Inclusions/HeaderIncludes.cpp +++ b/lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -9,6 +9,7 @@ #include "clang/Tooling/Inclusions/HeaderIncludes.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/FormatVariadic.h" namespace clang { @@ -50,12 +51,16 @@ unsigned getOffsetAfterTokenSequence( // Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is, // \p Tok will be the token after this directive; otherwise, it can be any token -// after the given \p Tok (including \p Tok). -bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) { +// after the given \p Tok (including \p Tok). If \p RawIDName is provided, the +// (second) raw_identifier name is checked. +bool checkAndConsumeDirectiveWithName( + Lexer &Lex, StringRef Name, Token &Tok, + llvm::Optional<StringRef> RawIDName = llvm::None) { bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) && Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) && - Tok.is(tok::raw_identifier); + Tok.is(tok::raw_identifier) && + (!RawIDName || Tok.getRawIdentifier() == *RawIDName); if (Matched) Lex.LexFromRawLexer(Tok); return Matched; @@ -68,24 +73,45 @@ void skipComments(Lexer &Lex, Token &Tok) { } // Returns the offset after header guard directives and any comments -// before/after header guards. If no header guard presents in the code, this -// will returns the offset after skipping all comments from the start of the -// code. +// before/after header guards (e.g. #ifndef/#define pair, #pragma once). If no +// header guard is present in the code, this will return the offset after +// skipping all comments from the start of the code. unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName, StringRef Code, const IncludeStyle &Style) { - return getOffsetAfterTokenSequence( - FileName, Code, Style, - [](const SourceManager &SM, Lexer &Lex, Token Tok) { - skipComments(Lex, Tok); - unsigned InitialOffset = SM.getFileOffset(Tok.getLocation()); - if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) { - skipComments(Lex, Tok); - if (checkAndConsumeDirectiveWithName(Lex, "define", Tok)) - return SM.getFileOffset(Tok.getLocation()); - } - return InitialOffset; - }); + // \p Consume returns location after header guard or 0 if no header guard is + // found. + auto ConsumeHeaderGuardAndComment = + [&](std::function<unsigned(const SourceManager &SM, Lexer &Lex, + Token Tok)> + Consume) { + return getOffsetAfterTokenSequence( + FileName, Code, Style, + [&Consume](const SourceManager &SM, Lexer &Lex, Token Tok) { + skipComments(Lex, Tok); + unsigned InitialOffset = SM.getFileOffset(Tok.getLocation()); + return std::max(InitialOffset, Consume(SM, Lex, Tok)); + }); + }; + return std::max( + // #ifndef/#define + ConsumeHeaderGuardAndComment( + [](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned { + if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) { + skipComments(Lex, Tok); + if (checkAndConsumeDirectiveWithName(Lex, "define", Tok)) + return SM.getFileOffset(Tok.getLocation()); + } + return 0; + }), + // #pragma once + ConsumeHeaderGuardAndComment( + [](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned { + if (checkAndConsumeDirectiveWithName(Lex, "pragma", Tok, + StringRef("once"))) + return SM.getFileOffset(Tok.getLocation()); + return 0; + })); } // Check if a sequence of tokens is like |