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