• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines the MultipleIncludeOpt interface.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H
15 #define LLVM_CLANG_MULTIPLEINCLUDEOPT_H
16 
17 namespace clang {
18 class IdentifierInfo;
19 
20 /// MultipleIncludeOpt - This class implements the simple state machine that the
21 /// Lexer class uses to detect files subject to the 'multiple-include'
22 /// optimization.  The public methods in this class are triggered by various
23 /// events that occur when a file is lexed, and after the entire file is lexed,
24 /// information about which macro (if any) controls the header is returned.
25 class MultipleIncludeOpt {
26   /// ReadAnyTokens - This is set to false when a file is first opened and true
27   /// any time a token is returned to the client or a (non-multiple-include)
28   /// directive is parsed.  When the final #endif is parsed this is reset back
29   /// to false, that way any tokens before the first #ifdef or after the last
30   /// #endif can be easily detected.
31   bool ReadAnyTokens;
32 
33   /// ReadAnyTokens - This is set to false when a file is first opened and true
34   /// any time a token is returned to the client or a (non-multiple-include)
35   /// directive is parsed.  When the final #endif is parsed this is reset back
36   /// to false, that way any tokens before the first #ifdef or after the last
37   /// #endif can be easily detected.
38   bool DidMacroExpansion;
39 
40   /// TheMacro - The controlling macro for a file, if valid.
41   ///
42   const IdentifierInfo *TheMacro;
43 public:
MultipleIncludeOpt()44   MultipleIncludeOpt() {
45     ReadAnyTokens = false;
46     DidMacroExpansion = false;
47     TheMacro = 0;
48   }
49 
50   /// Invalidate - Permanently mark this file as not being suitable for the
51   /// include-file optimization.
Invalidate()52   void Invalidate() {
53     // If we have read tokens but have no controlling macro, the state-machine
54     // below can never "accept".
55     ReadAnyTokens = true;
56     TheMacro = 0;
57   }
58 
59   /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the
60   /// top of the file when reading preprocessor directives.  Otherwise, reading
61   /// the "ifndef x" would count as reading tokens.
getHasReadAnyTokensVal()62   bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
63 
64   // If a token is read, remember that we have seen a side-effect in this file.
ReadToken()65   void ReadToken() { ReadAnyTokens = true; }
66 
67   /// ExpandedMacro - When a macro is expanded with this lexer as the current
68   /// buffer, this method is called to disable the MIOpt if needed.
ExpandedMacro()69   void ExpandedMacro() { DidMacroExpansion = true; }
70 
71   /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the
72   /// "#if !defined" equivalent) without any preceding tokens, this method is
73   /// called.
74   ///
75   /// Note, we don't care about the input value of 'ReadAnyTokens'.  The caller
76   /// ensures that this is only called if there are no tokens read before the
77   /// #ifndef.  The caller is required to do this, because reading the #if line
78   /// obviously reads in in tokens.
EnterTopLevelIFNDEF(const IdentifierInfo * M)79   void EnterTopLevelIFNDEF(const IdentifierInfo *M) {
80     // If the macro is already set, this is after the top-level #endif.
81     if (TheMacro)
82       return Invalidate();
83 
84     // If we have already expanded a macro by the end of the #ifndef line, then
85     // there is a macro expansion *in* the #ifndef line.  This means that the
86     // condition could evaluate differently when subsequently #included.  Reject
87     // this.
88     if (DidMacroExpansion)
89       return Invalidate();
90 
91     // Remember that we're in the #if and that we have the macro.
92     ReadAnyTokens = true;
93     TheMacro = M;
94   }
95 
96   /// EnterTopLevelConditional - This is invoked when a top level conditional
97   /// (except #ifndef) is found.
EnterTopLevelConditional()98   void EnterTopLevelConditional() {
99     /// If a conditional directive (except #ifndef) is found at the top level,
100     /// there is a chunk of the file not guarded by the controlling macro.
101     Invalidate();
102   }
103 
104   /// ExitTopLevelConditional - This method is called when the lexer exits the
105   /// top-level conditional.
ExitTopLevelConditional()106   void ExitTopLevelConditional() {
107     // If we have a macro, that means the top of the file was ok.  Set our state
108     // back to "not having read any tokens" so we can detect anything after the
109     // #endif.
110     if (!TheMacro) return Invalidate();
111 
112     // At this point, we haven't "read any tokens" but we do have a controlling
113     // macro.
114     ReadAnyTokens = false;
115   }
116 
117   /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if
118   /// there is a controlling macro, return it.
GetControllingMacroAtEndOfFile()119   const IdentifierInfo *GetControllingMacroAtEndOfFile() const {
120     // If we haven't read any tokens after the #endif, return the controlling
121     // macro if it's valid (if it isn't, it will be null).
122     if (!ReadAnyTokens)
123       return TheMacro;
124     return 0;
125   }
126 };
127 
128 }  // end namespace clang
129 
130 #endif
131