Add libclang support for label statements, gotos, and taking the
address of a label (GNU extension).



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113564 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index c899f5d..73e5ce0 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -359,7 +359,7 @@
   // Statement visitors
   bool VisitStmt(Stmt *S);
   bool VisitDeclStmt(DeclStmt *S);
-  // FIXME: LabelStmt label?
+  bool VisitGotoStmt(GotoStmt *S);
   bool VisitIfStmt(IfStmt *S);
   bool VisitSwitchStmt(SwitchStmt *S);
   bool VisitCaseStmt(CaseStmt *S);
@@ -377,7 +377,7 @@
   bool VisitOffsetOfExpr(OffsetOfExpr *E);
   bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
   bool VisitMemberExpr(MemberExpr *E);
-  // FIXME: AddrLabelExpr (once we have cursors for labels)
+  bool VisitAddrLabelExpr(AddrLabelExpr *E);
   bool VisitTypesCompatibleExpr(TypesCompatibleExpr *E);
   bool VisitVAArgExpr(VAArgExpr *E);
   bool VisitInitListExpr(InitListExpr *E);
@@ -1438,6 +1438,10 @@
   return false;
 }
 
+bool CursorVisitor::VisitGotoStmt(GotoStmt *S) {
+  return Visit(MakeCursorLabelRef(S->getLabel(), S->getLabelLoc(), TU));
+}
+
 bool CursorVisitor::VisitIfStmt(IfStmt *S) {
   if (VarDecl *Var = S->getConditionVariable()) {
     if (Visit(MakeCXCursor(Var, TU)))
@@ -1640,6 +1644,10 @@
   return VisitExpr(E);
 }
 
+bool CursorVisitor::VisitAddrLabelExpr(AddrLabelExpr *E) {
+  return Visit(MakeCursorLabelRef(E->getLabel(), E->getLabelLoc(), TU));
+}
+
 bool CursorVisitor::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
   return Visit(E->getArgTInfo1()->getTypeLoc()) || 
          Visit(E->getArgTInfo2()->getTypeLoc());
@@ -2603,6 +2611,13 @@
       return createCXString(Field->getNameAsString());
     }
 
+    case CXCursor_LabelRef: {
+      LabelStmt *Label = getCursorLabelRef(C).first;
+      assert(Label && "Missing label");
+      
+      return createCXString(Label->getID()->getName());
+    }
+
     default:
       return createCXString("<not implemented>");
     }
@@ -2615,6 +2630,14 @@
     return createCXString("");
   }
 
+  if (clang_isStatement(C.kind)) {
+    Stmt *S = getCursorStmt(C);
+    if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
+      return createCXString(Label->getID()->getName());
+
+    return createCXString("");
+  }
+  
   if (C.kind == CXCursor_MacroInstantiation)
     return createCXString(getCursorMacroInstantiation(C)->getName()
                                                            ->getNameStart());
@@ -2687,6 +2710,8 @@
     return createCXString("NamespaceRef");
   case CXCursor_MemberRef:
     return createCXString("MemberRef");
+  case CXCursor_LabelRef:
+    return createCXString("LabelRef");
   case CXCursor_UnexposedExpr:
       return createCXString("UnexposedExpr");
   case CXCursor_BlockExpr:
@@ -2701,6 +2726,8 @@
       return createCXString("ObjCMessageExpr");
   case CXCursor_UnexposedStmt:
       return createCXString("UnexposedStmt");
+  case CXCursor_LabelStmt:
+      return createCXString("LabelStmt");
   case CXCursor_InvalidFile:
       return createCXString("InvalidFile");
   case CXCursor_InvalidCode:
@@ -2899,6 +2926,11 @@
       return clang_getNullLocation();
     }
 
+    case CXCursor_LabelRef: {
+      std::pair<LabelStmt *, SourceLocation> P = getCursorLabelRef(C);
+      return cxloc::translateSourceLocation(getCursorContext(C), P.second);
+    }
+
     default:
       // FIXME: Need a way to enumerate all non-reference cases.
       llvm_unreachable("Missed a reference kind");
@@ -2909,6 +2941,10 @@
     return cxloc::translateSourceLocation(getCursorContext(C),
                                    getLocationFromExpr(getCursorExpr(C)));
 
+  if (clang_isStatement(C.kind))
+    return cxloc::translateSourceLocation(getCursorContext(C),
+                                          getCursorStmt(C)->getLocStart());
+
   if (C.kind == CXCursor_PreprocessingDirective) {
     SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin();
     return cxloc::translateSourceLocation(getCursorContext(C), L);
@@ -2965,6 +3001,9 @@
       // FIXME: Figure out what source range to use for a CXBaseSpecifier.
       return SourceRange();
 
+    case CXCursor_LabelRef:
+      return getCursorLabelRef(C).second;
+
     default:
       // FIXME: Need a way to enumerate all non-reference cases.
       llvm_unreachable("Missed a reference kind");
@@ -3017,6 +3056,15 @@
     return clang_getNullCursor();
   }
 
+  if (clang_isStatement(C.kind)) {
+    Stmt *S = getCursorStmt(C);
+    if (GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S))
+      return MakeCXCursor(Goto->getLabel(), getCursorDecl(C), 
+                          getCursorASTUnit(C));
+
+    return clang_getNullCursor();
+  }
+  
   if (C.kind == CXCursor_MacroInstantiation) {
     if (MacroDefinition *Def = getCursorMacroInstantiation(C)->getDefinition())
       return MakeMacroDefinitionCursor(Def, CXXUnit);
@@ -3053,6 +3101,13 @@
                                                          CXXUnit));
     }
 
+    case CXCursor_LabelRef:
+      // FIXME: We end up faking the "parent" declaration here because we
+      // don't want to make CXCursor larger.
+      return MakeCXCursor(getCursorLabelRef(C).first, 
+                          CXXUnit->getASTContext().getTranslationUnitDecl(),
+                          CXXUnit);
+
     default:
       // We would prefer to enumerate all non-reference cursor kinds here.
       llvm_unreachable("Unhandled reference cursor kind");
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 53145a6..6e5f61f 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -65,7 +65,6 @@
   case Stmt::CompoundStmtClass:
   case Stmt::CaseStmtClass:
   case Stmt::DefaultStmtClass:
-  case Stmt::LabelStmtClass:       
   case Stmt::IfStmtClass:          
   case Stmt::SwitchStmtClass:      
   case Stmt::WhileStmtClass:       
@@ -90,6 +89,10 @@
     K = CXCursor_UnexposedStmt;
     break;
       
+  case Stmt::LabelStmtClass:       
+    K = CXCursor_LabelStmt;
+    break;
+      
   case Stmt::PredefinedExprClass:        
   case Stmt::IntegerLiteralClass:        
   case Stmt::FloatingLiteralClass:       
@@ -153,6 +156,7 @@
   case Stmt::BlockExprClass:  
     K = CXCursor_UnexposedExpr;
     break;
+      
   case Stmt::DeclRefExprClass:           
   case Stmt::BlockDeclRefExprClass:
     // FIXME: UnresolvedLookupExpr?
@@ -357,6 +361,23 @@
   return static_cast<MacroInstantiation *>(C.data[0]);
 }
 
+CXCursor cxcursor::MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, 
+                                      ASTUnit *TU) {
+  
+  assert(Label && TU && "Invalid arguments!");
+  void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+  CXCursor C = { CXCursor_LabelRef, { Label, RawLoc, TU } };
+  return C;    
+}
+
+std::pair<LabelStmt*, SourceLocation> 
+cxcursor::getCursorLabelRef(CXCursor C) {
+  assert(C.kind == CXCursor_LabelRef);
+  return std::make_pair(static_cast<LabelStmt *>(C.data[0]),
+                        SourceLocation::getFromRawEncoding(
+                                       reinterpret_cast<uintptr_t>(C.data[1])));  
+}
+
 Decl *cxcursor::getCursorDecl(CXCursor Cursor) {
   return (Decl *)Cursor.data[0];
 }
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index eff71f3..743b38b 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -27,6 +27,7 @@
 class Decl;
 class Expr;
 class FieldDecl;
+class LabelStmt;
 class MacroDefinition;
 class MacroInstantiation;
 class NamedDecl;
@@ -128,6 +129,13 @@
 /// source range.
 MacroInstantiation *getCursorMacroInstantiation(CXCursor C);
 
+/// \brief Create a label reference at the given location.
+CXCursor MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, ASTUnit *TU);
+
+/// \brief Unpack a label reference into the label statement it refers to and
+/// the location of the reference.
+std::pair<LabelStmt *, SourceLocation> getCursorLabelRef(CXCursor C);
+  
 Decl *getCursorDecl(CXCursor Cursor);
 Expr *getCursorExpr(CXCursor Cursor);
 Stmt *getCursorStmt(CXCursor Cursor);