1//===--- PPConditionalDirectiveRecord.h - Preprocessing Directives-*- 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//  This file implements the PPConditionalDirectiveRecord class, which maintains
10//  a record of conditional directive regions.
11//
12//===----------------------------------------------------------------------===//
13#include "clang/Lex/PPConditionalDirectiveRecord.h"
14#include "llvm/Support/Capacity.h"
15
16using namespace clang;
17
18PPConditionalDirectiveRecord::PPConditionalDirectiveRecord(SourceManager &SM)
19  : SourceMgr(SM) {
20  CondDirectiveStack.push_back(SourceLocation());
21}
22
23bool PPConditionalDirectiveRecord::rangeIntersectsConditionalDirective(
24                                                      SourceRange Range) const {
25  if (Range.isInvalid())
26    return false;
27
28  CondDirectiveLocsTy::const_iterator low = llvm::lower_bound(
29      CondDirectiveLocs, Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr));
30  if (low == CondDirectiveLocs.end())
31    return false;
32
33  if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc()))
34    return false;
35
36  CondDirectiveLocsTy::const_iterator
37    upp = std::upper_bound(low, CondDirectiveLocs.end(),
38                           Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr));
39  SourceLocation uppRegion;
40  if (upp != CondDirectiveLocs.end())
41    uppRegion = upp->getRegionLoc();
42
43  return low->getRegionLoc() != uppRegion;
44}
45
46SourceLocation PPConditionalDirectiveRecord::findConditionalDirectiveRegionLoc(
47                                                     SourceLocation Loc) const {
48  if (Loc.isInvalid())
49    return SourceLocation();
50  if (CondDirectiveLocs.empty())
51    return SourceLocation();
52
53  if (SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
54                                          Loc))
55    return CondDirectiveStack.back();
56
57  CondDirectiveLocsTy::const_iterator low = llvm::lower_bound(
58      CondDirectiveLocs, Loc, CondDirectiveLoc::Comp(SourceMgr));
59  assert(low != CondDirectiveLocs.end());
60  return low->getRegionLoc();
61}
62
63void PPConditionalDirectiveRecord::addCondDirectiveLoc(
64                                                      CondDirectiveLoc DirLoc) {
65  // Ignore directives in system headers.
66  if (SourceMgr.isInSystemHeader(DirLoc.getLoc()))
67    return;
68
69  assert(CondDirectiveLocs.empty() ||
70         SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
71                                             DirLoc.getLoc()));
72  CondDirectiveLocs.push_back(DirLoc);
73}
74
75void PPConditionalDirectiveRecord::If(SourceLocation Loc,
76                                      SourceRange ConditionRange,
77                                      ConditionValueKind ConditionValue) {
78  addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
79  CondDirectiveStack.push_back(Loc);
80}
81
82void PPConditionalDirectiveRecord::Ifdef(SourceLocation Loc,
83                                         const Token &MacroNameTok,
84                                         const MacroDefinition &MD) {
85  addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
86  CondDirectiveStack.push_back(Loc);
87}
88
89void PPConditionalDirectiveRecord::Ifndef(SourceLocation Loc,
90                                          const Token &MacroNameTok,
91                                          const MacroDefinition &MD) {
92  addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
93  CondDirectiveStack.push_back(Loc);
94}
95
96void PPConditionalDirectiveRecord::Elif(SourceLocation Loc,
97                                        SourceRange ConditionRange,
98                                        ConditionValueKind ConditionValue,
99                                        SourceLocation IfLoc) {
100  addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
101  CondDirectiveStack.back() = Loc;
102}
103
104void PPConditionalDirectiveRecord::Else(SourceLocation Loc,
105                                        SourceLocation IfLoc) {
106  addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
107  CondDirectiveStack.back() = Loc;
108}
109
110void PPConditionalDirectiveRecord::Endif(SourceLocation Loc,
111                                         SourceLocation IfLoc) {
112  addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
113  assert(!CondDirectiveStack.empty());
114  CondDirectiveStack.pop_back();
115}
116
117size_t PPConditionalDirectiveRecord::getTotalMemory() const {
118  return llvm::capacity_in_bytes(CondDirectiveLocs);
119}
120