Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===// |
| 2 | // |
||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
| 6 | // |
||
| 7 | //===----------------------------------------------------------------------===// |
||
| 8 | /// |
||
| 9 | /// \file |
||
| 10 | /// Defines the MultipleIncludeOpt interface. |
||
| 11 | // |
||
| 12 | //===----------------------------------------------------------------------===// |
||
| 13 | |||
| 14 | #ifndef LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H |
||
| 15 | #define LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H |
||
| 16 | |||
| 17 | #include "clang/Basic/SourceLocation.h" |
||
| 18 | |||
| 19 | namespace clang { |
||
| 20 | class IdentifierInfo; |
||
| 21 | |||
| 22 | /// Implements the simple state machine that the Lexer class uses to |
||
| 23 | /// detect files subject to the 'multiple-include' optimization. |
||
| 24 | /// |
||
| 25 | /// The public methods in this class are triggered by various |
||
| 26 | /// events that occur when a file is lexed, and after the entire file is lexed, |
||
| 27 | /// information about which macro (if any) controls the header is returned. |
||
| 28 | class MultipleIncludeOpt { |
||
| 29 | /// ReadAnyTokens - This is set to false when a file is first opened and true |
||
| 30 | /// any time a token is returned to the client or a (non-multiple-include) |
||
| 31 | /// directive is parsed. When the final \#endif is parsed this is reset back |
||
| 32 | /// to false, that way any tokens before the first \#ifdef or after the last |
||
| 33 | /// \#endif can be easily detected. |
||
| 34 | bool ReadAnyTokens; |
||
| 35 | |||
| 36 | /// ImmediatelyAfterTopLevelIfndef - This is true when the only tokens |
||
| 37 | /// processed in the file so far is an #ifndef and an identifier. Used in |
||
| 38 | /// the detection of header guards in a file. |
||
| 39 | bool ImmediatelyAfterTopLevelIfndef; |
||
| 40 | |||
| 41 | /// ReadAnyTokens - This is set to false when a file is first opened and true |
||
| 42 | /// any time a token is returned to the client or a (non-multiple-include) |
||
| 43 | /// directive is parsed. When the final #endif is parsed this is reset back |
||
| 44 | /// to false, that way any tokens before the first #ifdef or after the last |
||
| 45 | /// #endif can be easily detected. |
||
| 46 | bool DidMacroExpansion; |
||
| 47 | |||
| 48 | /// TheMacro - The controlling macro for a file, if valid. |
||
| 49 | /// |
||
| 50 | const IdentifierInfo *TheMacro; |
||
| 51 | |||
| 52 | /// DefinedMacro - The macro defined right after TheMacro, if any. |
||
| 53 | const IdentifierInfo *DefinedMacro; |
||
| 54 | |||
| 55 | SourceLocation MacroLoc; |
||
| 56 | SourceLocation DefinedLoc; |
||
| 57 | public: |
||
| 58 | MultipleIncludeOpt() { |
||
| 59 | ReadAnyTokens = false; |
||
| 60 | ImmediatelyAfterTopLevelIfndef = false; |
||
| 61 | DidMacroExpansion = false; |
||
| 62 | TheMacro = nullptr; |
||
| 63 | DefinedMacro = nullptr; |
||
| 64 | } |
||
| 65 | |||
| 66 | SourceLocation GetMacroLocation() const { |
||
| 67 | return MacroLoc; |
||
| 68 | } |
||
| 69 | |||
| 70 | SourceLocation GetDefinedLocation() const { |
||
| 71 | return DefinedLoc; |
||
| 72 | } |
||
| 73 | |||
| 74 | void resetImmediatelyAfterTopLevelIfndef() { |
||
| 75 | ImmediatelyAfterTopLevelIfndef = false; |
||
| 76 | } |
||
| 77 | |||
| 78 | void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) { |
||
| 79 | DefinedMacro = M; |
||
| 80 | DefinedLoc = Loc; |
||
| 81 | } |
||
| 82 | |||
| 83 | /// Invalidate - Permanently mark this file as not being suitable for the |
||
| 84 | /// include-file optimization. |
||
| 85 | void Invalidate() { |
||
| 86 | // If we have read tokens but have no controlling macro, the state-machine |
||
| 87 | // below can never "accept". |
||
| 88 | ReadAnyTokens = true; |
||
| 89 | ImmediatelyAfterTopLevelIfndef = false; |
||
| 90 | DefinedMacro = nullptr; |
||
| 91 | TheMacro = nullptr; |
||
| 92 | } |
||
| 93 | |||
| 94 | /// getHasReadAnyTokensVal - This is used for the \#ifndef handshake at the |
||
| 95 | /// top of the file when reading preprocessor directives. Otherwise, reading |
||
| 96 | /// the "ifndef x" would count as reading tokens. |
||
| 97 | bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } |
||
| 98 | |||
| 99 | /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive |
||
| 100 | /// was an #ifndef at the beginning of the file. |
||
| 101 | bool getImmediatelyAfterTopLevelIfndef() const { |
||
| 102 | return ImmediatelyAfterTopLevelIfndef; |
||
| 103 | } |
||
| 104 | |||
| 105 | // If a token is read, remember that we have seen a side-effect in this file. |
||
| 106 | void ReadToken() { |
||
| 107 | ReadAnyTokens = true; |
||
| 108 | ImmediatelyAfterTopLevelIfndef = false; |
||
| 109 | } |
||
| 110 | |||
| 111 | /// ExpandedMacro - When a macro is expanded with this lexer as the current |
||
| 112 | /// buffer, this method is called to disable the MIOpt if needed. |
||
| 113 | void ExpandedMacro() { DidMacroExpansion = true; } |
||
| 114 | |||
| 115 | /// Called when entering a top-level \#ifndef directive (or the |
||
| 116 | /// "\#if !defined" equivalent) without any preceding tokens. |
||
| 117 | /// |
||
| 118 | /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller |
||
| 119 | /// ensures that this is only called if there are no tokens read before the |
||
| 120 | /// \#ifndef. The caller is required to do this, because reading the \#if |
||
| 121 | /// line obviously reads in tokens. |
||
| 122 | void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) { |
||
| 123 | // If the macro is already set, this is after the top-level #endif. |
||
| 124 | if (TheMacro) |
||
| 125 | return Invalidate(); |
||
| 126 | |||
| 127 | // If we have already expanded a macro by the end of the #ifndef line, then |
||
| 128 | // there is a macro expansion *in* the #ifndef line. This means that the |
||
| 129 | // condition could evaluate differently when subsequently #included. Reject |
||
| 130 | // this. |
||
| 131 | if (DidMacroExpansion) |
||
| 132 | return Invalidate(); |
||
| 133 | |||
| 134 | // Remember that we're in the #if and that we have the macro. |
||
| 135 | ReadAnyTokens = true; |
||
| 136 | ImmediatelyAfterTopLevelIfndef = true; |
||
| 137 | TheMacro = M; |
||
| 138 | MacroLoc = Loc; |
||
| 139 | } |
||
| 140 | |||
| 141 | /// Invoked when a top level conditional (except \#ifndef) is found. |
||
| 142 | void EnterTopLevelConditional() { |
||
| 143 | // If a conditional directive (except #ifndef) is found at the top level, |
||
| 144 | // there is a chunk of the file not guarded by the controlling macro. |
||
| 145 | Invalidate(); |
||
| 146 | } |
||
| 147 | |||
| 148 | /// Called when the lexer exits the top-level conditional. |
||
| 149 | void ExitTopLevelConditional() { |
||
| 150 | // If we have a macro, that means the top of the file was ok. Set our state |
||
| 151 | // back to "not having read any tokens" so we can detect anything after the |
||
| 152 | // #endif. |
||
| 153 | if (!TheMacro) return Invalidate(); |
||
| 154 | |||
| 155 | // At this point, we haven't "read any tokens" but we do have a controlling |
||
| 156 | // macro. |
||
| 157 | ReadAnyTokens = false; |
||
| 158 | ImmediatelyAfterTopLevelIfndef = false; |
||
| 159 | } |
||
| 160 | |||
| 161 | /// Once the entire file has been lexed, if there is a controlling |
||
| 162 | /// macro, return it. |
||
| 163 | const IdentifierInfo *GetControllingMacroAtEndOfFile() const { |
||
| 164 | // If we haven't read any tokens after the #endif, return the controlling |
||
| 165 | // macro if it's valid (if it isn't, it will be null). |
||
| 166 | if (!ReadAnyTokens) |
||
| 167 | return TheMacro; |
||
| 168 | return nullptr; |
||
| 169 | } |
||
| 170 | |||
| 171 | /// If the ControllingMacro is followed by a macro definition, return |
||
| 172 | /// the macro that was defined. |
||
| 173 | const IdentifierInfo *GetDefinedMacro() const { |
||
| 174 | return DefinedMacro; |
||
| 175 | } |
||
| 176 | }; |
||
| 177 | |||
| 178 | } // end namespace clang |
||
| 179 | |||
| 180 | #endif |