When associating file ranges of macro arguments with their
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sat, 20 Oct 2012 00:51:32 +0000 (00:51 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sat, 20 Oct 2012 00:51:32 +0000 (00:51 +0000)
macro expansion ranges, make sure to check all the FileID
entries that are contained in the spelling range of the
expansion for the macro argument.

Fixes rdar://12537982

llvm-svn: 166359

clang/include/clang/Basic/SourceManager.h
clang/lib/Basic/SourceManager.cpp
clang/test/Index/get-cursor-macro-args.h
clang/test/Index/get-cursor-macro-args.m

index 0478ab8133c841f765e3e38101259bcd850c892a..a8e10ecf758a83bef014faaf57d837389c4fcdd4 100644 (file)
@@ -1556,7 +1556,11 @@ private:
   getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
                                    unsigned Offset) const;
   void computeMacroArgsCache(MacroArgsMap *&MacroArgsCache, FileID FID) const;
-
+  void associateFileChunkWithMacroArgExp(MacroArgsMap &MacroArgsCache,
+                                         FileID FID,
+                                         SourceLocation SpellLoc,
+                                         SourceLocation ExpansionLoc,
+                                         unsigned ExpansionLength) const;
   friend class ASTReader;
   friend class ASTWriter;
 };
index 603b38592603ef1bb849925383b3a4d82ec5af8a..cd0284a18e5dea5e50f191fc7d29c48338f51f25 100644 (file)
@@ -1705,46 +1705,91 @@ void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr,
     if (!ExpInfo.isMacroArgExpansion())
       continue;
 
-    SourceLocation SpellLoc = ExpInfo.getSpellingLoc();
-    while (!SpellLoc.isFileID()) {
-      std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(SpellLoc);
-      const ExpansionInfo &Info = getSLocEntry(LocInfo.first).getExpansion();
-      if (!Info.isMacroArgExpansion())
-        break;
-      SpellLoc = Info.getSpellingLoc().getLocWithOffset(LocInfo.second);
+    associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
+                                 ExpInfo.getSpellingLoc(),
+                                 SourceLocation::getMacroLoc(Entry.getOffset()),
+                                 getFileIDSize(FileID::get(ID)));
+  }
+}
+
+void SourceManager::associateFileChunkWithMacroArgExp(
+                                         MacroArgsMap &MacroArgsCache,
+                                         FileID FID,
+                                         SourceLocation SpellLoc,
+                                         SourceLocation ExpansionLoc,
+                                         unsigned ExpansionLength) const {
+  if (!SpellLoc.isFileID()) {
+    unsigned SpellBeginOffs = SpellLoc.getOffset();
+    unsigned SpellEndOffs = SpellBeginOffs + ExpansionLength;
+
+    // The spelling range for this macro argument expansion can span multiple
+    // consecutive FileID entries. Go through each entry contained in the
+    // spelling range and if one is itself a macro argument expansion, recurse
+    // and associate the file chunk that it represents.
+
+    FileID SpellFID; // Current FileID in the spelling range.
+    unsigned SpellRelativeOffs;
+    llvm::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc);
+    while (1) {
+      const SLocEntry &Entry = getSLocEntry(SpellFID);
+      unsigned SpellFIDBeginOffs = Entry.getOffset();
+      unsigned SpellFIDSize = getFileIDSize(SpellFID);
+      unsigned SpellFIDEndOffs = SpellFIDBeginOffs + SpellFIDSize;
+      const ExpansionInfo &Info = Entry.getExpansion();
+      if (Info.isMacroArgExpansion()) {
+        unsigned CurrSpellLength;
+        if (SpellFIDEndOffs < SpellEndOffs)
+          CurrSpellLength = SpellFIDSize - SpellRelativeOffs;
+        else
+          CurrSpellLength = ExpansionLength;
+        associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
+                      Info.getSpellingLoc().getLocWithOffset(SpellRelativeOffs),
+                      ExpansionLoc, CurrSpellLength);
+      }
+
+      if (SpellFIDEndOffs >= SpellEndOffs)
+        return; // we covered all FileID entries in the spelling range.
+
+      // Move to the next FileID entry in the spelling range.
+      unsigned advance = SpellFIDSize - SpellRelativeOffs + 1;
+      ExpansionLoc = ExpansionLoc.getLocWithOffset(advance);
+      ExpansionLength -= advance;
+      ++SpellFID.ID;
+      SpellRelativeOffs = 0;
     }
-    if (!SpellLoc.isFileID())
-      continue;
-    
-    unsigned BeginOffs;
-    if (!isInFileID(SpellLoc, FID, &BeginOffs))
-      continue;
 
-    unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID));
-
-    // Add a new chunk for this macro argument. A previous macro argument chunk
-    // may have been lexed again, so e.g. if the map is
-    //     0   -> SourceLocation()
-    //     100 -> Expanded loc #1
-    //     110 -> SourceLocation()
-    // and we found a new macro FileID that lexed from offet 105 with length 3,
-    // the new map will be:
-    //     0   -> SourceLocation()
-    //     100 -> Expanded loc #1
-    //     105 -> Expanded loc #2
-    //     108 -> Expanded loc #1
-    //     110 -> SourceLocation()
-    //
-    // Since re-lexed macro chunks will always be the same size or less of
-    // previous chunks, we only need to find where the ending of the new macro
-    // chunk is mapped to and update the map with new begin/end mappings.
-
-    MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
-    --I;
-    SourceLocation EndOffsMappedLoc = I->second;
-    MacroArgsCache[BeginOffs] = SourceLocation::getMacroLoc(Entry.getOffset());
-    MacroArgsCache[EndOffs] = EndOffsMappedLoc;
   }
+
+  assert(SpellLoc.isFileID());
+
+  unsigned BeginOffs;
+  if (!isInFileID(SpellLoc, FID, &BeginOffs))
+    return;
+
+  unsigned EndOffs = BeginOffs + ExpansionLength;
+
+  // Add a new chunk for this macro argument. A previous macro argument chunk
+  // may have been lexed again, so e.g. if the map is
+  //     0   -> SourceLocation()
+  //     100 -> Expanded loc #1
+  //     110 -> SourceLocation()
+  // and we found a new macro FileID that lexed from offet 105 with length 3,
+  // the new map will be:
+  //     0   -> SourceLocation()
+  //     100 -> Expanded loc #1
+  //     105 -> Expanded loc #2
+  //     108 -> Expanded loc #1
+  //     110 -> SourceLocation()
+  //
+  // Since re-lexed macro chunks will always be the same size or less of
+  // previous chunks, we only need to find where the ending of the new macro
+  // chunk is mapped to and update the map with new begin/end mappings.
+
+  MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
+  --I;
+  SourceLocation EndOffsMappedLoc = I->second;
+  MacroArgsCache[BeginOffs] = ExpansionLoc;
+  MacroArgsCache[EndOffs] = EndOffsMappedLoc;
 }
 
 /// \brief If \arg Loc points inside a function macro argument, the returned
index 40ec8dc0b81fb706fc0dc935901fa3bcfad5938b..70d0dc7bf83293417f79aca0a6998bcbf36bf410 100644 (file)
@@ -2,8 +2,8 @@
 +(void)meth;
 @end
 
-#define MACRO2(x) x
-#define MACRO(x) MACRO2(x)
+#define MACRO2(x) (x)
+#define MACRO(x) MACRO2((x))
 
 void test() {
   MACRO([MyClass meth]);
index a439419b76ec9ffb9f2f4cd8596d10bfd131e827..d5ab72878f526496136130740be69a2f4340025e 100644 (file)
@@ -1,6 +1,8 @@
 // Test without PCH
 // RUN: c-index-test -cursor-at=%S/get-cursor-macro-args.h:9:12 \
 // RUN:              -cursor-at=%S/get-cursor-macro-args.h:9:21 \
+// RUN:              -cursor-at=%S/get-cursor-macro-args.h:9:9 \
+// RUN:              -cursor-at=%S/get-cursor-macro-args.h:9:22 \
 // RUN:              -cursor-at=%S/get-cursor-macro-args.h:15:12 \
 // RUN:              -cursor-at=%S/get-cursor-macro-args.h:15:20 \
 // RUN:       %s -include %S/get-cursor-macro-args.h | FileCheck %s
@@ -9,6 +11,8 @@
 // RUN: c-index-test -write-pch %t.pch -x objective-c-header %S/get-cursor-macro-args.h
 // RUN: c-index-test -cursor-at=%S/get-cursor-macro-args.h:9:12 \
 // RUN:              -cursor-at=%S/get-cursor-macro-args.h:9:21 \
+// RUN:              -cursor-at=%S/get-cursor-macro-args.h:9:9 \
+// RUN:              -cursor-at=%S/get-cursor-macro-args.h:9:22 \
 // RUN:              -cursor-at=%S/get-cursor-macro-args.h:15:12 \
 // RUN:              -cursor-at=%S/get-cursor-macro-args.h:15:20 \
 // RUN:       %s -include-pch %t.pch | FileCheck %s
@@ -16,4 +20,6 @@
 // CHECK:      ObjCClassRef=MyClass:1:12
 // CHECK-NEXT: ObjCMessageExpr=meth:2:8
 // CHECK-NEXT: ObjCMessageExpr=meth:2:8
+// CHECK-NEXT: ObjCMessageExpr=meth:2:8
+// CHECK-NEXT: ObjCMessageExpr=meth:2:8
 // CHECK-NEXT: ObjCClassRef=MyClass:1:12