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