MultipleIncludeOpt.h revision 071662d971e51ac64e0fe16d3baf9d85894b09a5
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/// \file
11/// \brief Defines the MultipleIncludeOpt interface.
12
13#ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H
14#define LLVM_CLANG_MULTIPLEINCLUDEOPT_H
15
16namespace clang {
17class IdentifierInfo;
18
19/// \brief Implements the simple state machine that the Lexer class uses to
20/// detect files subject to the 'multiple-include' optimization.
21///
22/// 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.
25class 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;
43public:
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.
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.
62  bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
63
64  // If a token is read, remember that we have seen a side-effect in this file.
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.
69  void ExpandedMacro() { DidMacroExpansion = true; }
70
71  /// \brief Called when entering a top-level \#ifndef directive (or the
72  /// "\#if !defined" equivalent) without any preceding tokens.
73  ///
74  /// Note, we don't care about the input value of 'ReadAnyTokens'.  The caller
75  /// ensures that this is only called if there are no tokens read before the
76  /// \#ifndef.  The caller is required to do this, because reading the \#if
77  /// line obviously reads in in tokens.
78  void EnterTopLevelIFNDEF(const IdentifierInfo *M) {
79    // If the macro is already set, this is after the top-level #endif.
80    if (TheMacro)
81      return Invalidate();
82
83    // If we have already expanded a macro by the end of the #ifndef line, then
84    // there is a macro expansion *in* the #ifndef line.  This means that the
85    // condition could evaluate differently when subsequently #included.  Reject
86    // this.
87    if (DidMacroExpansion)
88      return Invalidate();
89
90    // Remember that we're in the #if and that we have the macro.
91    ReadAnyTokens = true;
92    TheMacro = M;
93  }
94
95  /// \brief Invoked when a top level conditional (except \#ifndef) is found.
96  void EnterTopLevelConditional() {
97    /// If a conditional directive (except #ifndef) is found at the top level,
98    /// there is a chunk of the file not guarded by the controlling macro.
99    Invalidate();
100  }
101
102  /// \brief Called when the lexer exits the top-level conditional.
103  void ExitTopLevelConditional() {
104    // If we have a macro, that means the top of the file was ok.  Set our state
105    // back to "not having read any tokens" so we can detect anything after the
106    // #endif.
107    if (!TheMacro) return Invalidate();
108
109    // At this point, we haven't "read any tokens" but we do have a controlling
110    // macro.
111    ReadAnyTokens = false;
112  }
113
114  /// \brief Once the entire file has been lexed, if there is a controlling
115  /// macro, return it.
116  const IdentifierInfo *GetControllingMacroAtEndOfFile() const {
117    // If we haven't read any tokens after the #endif, return the controlling
118    // macro if it's valid (if it isn't, it will be null).
119    if (!ReadAnyTokens)
120      return TheMacro;
121    return 0;
122  }
123};
124
125}  // end namespace clang
126
127#endif
128