MacroInfo.cpp revision aa93a875605536d72a10359a0098396192b7d4ec
1//===--- MacroInfo.cpp - Information about #defined identifiers -----------===//
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 implements the MacroInfo interface.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Lex/MacroInfo.h"
15#include "clang/Lex/Preprocessor.h"
16using namespace clang;
17
18MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
19  IsFunctionLike = false;
20  IsC99Varargs = false;
21  IsGNUVarargs = false;
22  IsBuiltinMacro = false;
23  IsFromAST = false;
24  ChangedAfterLoad = false;
25  IsDisabled = false;
26  IsUsed = false;
27  IsAllowRedefinitionsWithoutWarning = false;
28  IsWarnIfUnused = false;
29  IsDefinitionLengthCached = false;
30  IsPublic = true;
31
32  ArgumentList = 0;
33  NumArguments = 0;
34}
35
36MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
37  Location = MI.Location;
38  EndLocation = MI.EndLocation;
39  ReplacementTokens = MI.ReplacementTokens;
40  IsFunctionLike = MI.IsFunctionLike;
41  IsC99Varargs = MI.IsC99Varargs;
42  IsGNUVarargs = MI.IsGNUVarargs;
43  IsBuiltinMacro = MI.IsBuiltinMacro;
44  IsFromAST = MI.IsFromAST;
45  ChangedAfterLoad = MI.ChangedAfterLoad;
46  IsDisabled = MI.IsDisabled;
47  IsUsed = MI.IsUsed;
48  IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
49  IsWarnIfUnused = MI.IsWarnIfUnused;
50  IsDefinitionLengthCached = MI.IsDefinitionLengthCached;
51  DefinitionLength = MI.DefinitionLength;
52  IsPublic = MI.IsPublic;
53
54  ArgumentList = 0;
55  NumArguments = 0;
56  setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
57}
58
59unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
60  assert(!IsDefinitionLengthCached);
61  IsDefinitionLengthCached = true;
62
63  if (ReplacementTokens.empty())
64    return (DefinitionLength = 0);
65
66  const Token &firstToken = ReplacementTokens.front();
67  const Token &lastToken = ReplacementTokens.back();
68  SourceLocation macroStart = firstToken.getLocation();
69  SourceLocation macroEnd = lastToken.getLocation();
70  assert(macroStart.isValid() && macroEnd.isValid());
71  assert((macroStart.isFileID() || firstToken.is(tok::comment)) &&
72         "Macro defined in macro?");
73  assert((macroEnd.isFileID() || lastToken.is(tok::comment)) &&
74         "Macro defined in macro?");
75  std::pair<FileID, unsigned>
76      startInfo = SM.getDecomposedExpansionLoc(macroStart);
77  std::pair<FileID, unsigned>
78      endInfo = SM.getDecomposedExpansionLoc(macroEnd);
79  assert(startInfo.first == endInfo.first &&
80         "Macro definition spanning multiple FileIDs ?");
81  assert(startInfo.second <= endInfo.second);
82  DefinitionLength = endInfo.second - startInfo.second;
83  DefinitionLength += lastToken.getLength();
84
85  return DefinitionLength;
86}
87
88/// isIdenticalTo - Return true if the specified macro definition is equal to
89/// this macro in spelling, arguments, and whitespace.  This is used to emit
90/// duplicate definition warnings.  This implements the rules in C99 6.10.3.
91///
92bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
93  // Check # tokens in replacement, number of args, and various flags all match.
94  if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
95      getNumArgs() != Other.getNumArgs() ||
96      isFunctionLike() != Other.isFunctionLike() ||
97      isC99Varargs() != Other.isC99Varargs() ||
98      isGNUVarargs() != Other.isGNUVarargs())
99    return false;
100
101  // Check arguments.
102  for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
103       I != E; ++I, ++OI)
104    if (*I != *OI) return false;
105
106  // Check all the tokens.
107  for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
108    const Token &A = ReplacementTokens[i];
109    const Token &B = Other.ReplacementTokens[i];
110    if (A.getKind() != B.getKind())
111      return false;
112
113    // If this isn't the first first token, check that the whitespace and
114    // start-of-line characteristics match.
115    if (i != 0 &&
116        (A.isAtStartOfLine() != B.isAtStartOfLine() ||
117         A.hasLeadingSpace() != B.hasLeadingSpace()))
118      return false;
119
120    // If this is an identifier, it is easy.
121    if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
122      if (A.getIdentifierInfo() != B.getIdentifierInfo())
123        return false;
124      continue;
125    }
126
127    // Otherwise, check the spelling.
128    if (PP.getSpelling(A) != PP.getSpelling(B))
129      return false;
130  }
131
132  return true;
133}
134