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