|
|
|||
File indexing completed on 2026-05-10 08:36:57
0001 //===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 /// 0009 /// \file 0010 /// Defines the MultipleIncludeOpt interface. 0011 // 0012 //===----------------------------------------------------------------------===// 0013 0014 #ifndef LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H 0015 #define LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H 0016 0017 #include "clang/Basic/SourceLocation.h" 0018 0019 namespace clang { 0020 class IdentifierInfo; 0021 0022 /// Implements the simple state machine that the Lexer class uses to 0023 /// detect files subject to the 'multiple-include' optimization. 0024 /// 0025 /// The public methods in this class are triggered by various 0026 /// events that occur when a file is lexed, and after the entire file is lexed, 0027 /// information about which macro (if any) controls the header is returned. 0028 class MultipleIncludeOpt { 0029 /// ReadAnyTokens - This is set to false when a file is first opened and true 0030 /// any time a token is returned to the client or a (non-multiple-include) 0031 /// directive is parsed. When the final \#endif is parsed this is reset back 0032 /// to false, that way any tokens before the first \#ifdef or after the last 0033 /// \#endif can be easily detected. 0034 bool ReadAnyTokens; 0035 0036 /// ImmediatelyAfterTopLevelIfndef - This is true when the only tokens 0037 /// processed in the file so far is an #ifndef and an identifier. Used in 0038 /// the detection of header guards in a file. 0039 bool ImmediatelyAfterTopLevelIfndef; 0040 0041 /// ReadAnyTokens - This is set to false when a file is first opened and true 0042 /// any time a token is returned to the client or a (non-multiple-include) 0043 /// directive is parsed. When the final #endif is parsed this is reset back 0044 /// to false, that way any tokens before the first #ifdef or after the last 0045 /// #endif can be easily detected. 0046 bool DidMacroExpansion; 0047 0048 /// TheMacro - The controlling macro for a file, if valid. 0049 /// 0050 const IdentifierInfo *TheMacro; 0051 0052 /// DefinedMacro - The macro defined right after TheMacro, if any. 0053 const IdentifierInfo *DefinedMacro; 0054 0055 SourceLocation MacroLoc; 0056 SourceLocation DefinedLoc; 0057 public: 0058 MultipleIncludeOpt() { 0059 ReadAnyTokens = false; 0060 ImmediatelyAfterTopLevelIfndef = false; 0061 DidMacroExpansion = false; 0062 TheMacro = nullptr; 0063 DefinedMacro = nullptr; 0064 } 0065 0066 SourceLocation GetMacroLocation() const { 0067 return MacroLoc; 0068 } 0069 0070 SourceLocation GetDefinedLocation() const { 0071 return DefinedLoc; 0072 } 0073 0074 void resetImmediatelyAfterTopLevelIfndef() { 0075 ImmediatelyAfterTopLevelIfndef = false; 0076 } 0077 0078 void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) { 0079 DefinedMacro = M; 0080 DefinedLoc = Loc; 0081 } 0082 0083 /// Invalidate - Permanently mark this file as not being suitable for the 0084 /// include-file optimization. 0085 void Invalidate() { 0086 // If we have read tokens but have no controlling macro, the state-machine 0087 // below can never "accept". 0088 ReadAnyTokens = true; 0089 ImmediatelyAfterTopLevelIfndef = false; 0090 DefinedMacro = nullptr; 0091 TheMacro = nullptr; 0092 } 0093 0094 /// getHasReadAnyTokensVal - This is used for the \#ifndef handshake at the 0095 /// top of the file when reading preprocessor directives. Otherwise, reading 0096 /// the "ifndef x" would count as reading tokens. 0097 bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } 0098 0099 /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive 0100 /// was an #ifndef at the beginning of the file. 0101 bool getImmediatelyAfterTopLevelIfndef() const { 0102 return ImmediatelyAfterTopLevelIfndef; 0103 } 0104 0105 // If a token is read, remember that we have seen a side-effect in this file. 0106 void ReadToken() { 0107 ReadAnyTokens = true; 0108 ImmediatelyAfterTopLevelIfndef = false; 0109 } 0110 0111 /// SetReadToken - Set whether the value of 'ReadAnyTokens'. Called to 0112 /// override when encountering tokens outside of the include guard that have 0113 /// no effect if the file in question is is included multiple times (e.g. the 0114 /// null directive). 0115 void SetReadToken(bool Value) { ReadAnyTokens = Value; } 0116 0117 /// ExpandedMacro - When a macro is expanded with this lexer as the current 0118 /// buffer, this method is called to disable the MIOpt if needed. 0119 void ExpandedMacro() { DidMacroExpansion = true; } 0120 0121 /// Called when entering a top-level \#ifndef directive (or the 0122 /// "\#if !defined" equivalent) without any preceding tokens. 0123 /// 0124 /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller 0125 /// ensures that this is only called if there are no tokens read before the 0126 /// \#ifndef. The caller is required to do this, because reading the \#if 0127 /// line obviously reads in tokens. 0128 void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) { 0129 // If the macro is already set, this is after the top-level #endif. 0130 if (TheMacro) 0131 return Invalidate(); 0132 0133 // If we have already expanded a macro by the end of the #ifndef line, then 0134 // there is a macro expansion *in* the #ifndef line. This means that the 0135 // condition could evaluate differently when subsequently #included. Reject 0136 // this. 0137 if (DidMacroExpansion) 0138 return Invalidate(); 0139 0140 // Remember that we're in the #if and that we have the macro. 0141 ReadAnyTokens = true; 0142 ImmediatelyAfterTopLevelIfndef = true; 0143 TheMacro = M; 0144 MacroLoc = Loc; 0145 } 0146 0147 /// Invoked when a top level conditional (except \#ifndef) is found. 0148 void EnterTopLevelConditional() { 0149 // If a conditional directive (except #ifndef) is found at the top level, 0150 // there is a chunk of the file not guarded by the controlling macro. 0151 Invalidate(); 0152 } 0153 0154 /// Called when the lexer exits the top-level conditional. 0155 void ExitTopLevelConditional() { 0156 // If we have a macro, that means the top of the file was ok. Set our state 0157 // back to "not having read any tokens" so we can detect anything after the 0158 // #endif. 0159 if (!TheMacro) return Invalidate(); 0160 0161 // At this point, we haven't "read any tokens" but we do have a controlling 0162 // macro. 0163 ReadAnyTokens = false; 0164 ImmediatelyAfterTopLevelIfndef = false; 0165 } 0166 0167 /// Once the entire file has been lexed, if there is a controlling 0168 /// macro, return it. 0169 const IdentifierInfo *GetControllingMacroAtEndOfFile() const { 0170 // If we haven't read any tokens after the #endif, return the controlling 0171 // macro if it's valid (if it isn't, it will be null). 0172 if (!ReadAnyTokens) 0173 return TheMacro; 0174 return nullptr; 0175 } 0176 0177 /// If the ControllingMacro is followed by a macro definition, return 0178 /// the macro that was defined. 0179 const IdentifierInfo *GetDefinedMacro() const { 0180 return DefinedMacro; 0181 } 0182 }; 0183 0184 } // end namespace clang 0185 0186 #endif
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|