diff options
Diffstat (limited to 'tools/CIndex/CIndex.cpp')
| -rw-r--r-- | tools/CIndex/CIndex.cpp | 265 | 
1 files changed, 223 insertions, 42 deletions
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 663b32fa1a06e..1000818692a0d 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -158,31 +158,12 @@ static RangeComparisonResult RangeCompare(SourceManager &SM,  CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,                                            const LangOptions &LangOpts,                                            SourceRange R) { -  // FIXME: This is largely copy-paste from -  // TextDiagnosticPrinter::HighlightRange.  When it is clear that this is what -  // we want the two routines should be refactored. -    // We want the last character in this location, so we will adjust the -  // instantiation location accordingly. - -  // If the location is from a macro instantiation, get the end of the -  // instantiation range. +  // location accordingly. +  // FIXME: How do do this with a macro instantiation location?    SourceLocation EndLoc = R.getEnd(); -  SourceLocation InstLoc = SM.getInstantiationLoc(EndLoc); -  if (EndLoc.isMacroID()) -    InstLoc = SM.getInstantiationRange(EndLoc).second; - -  // Measure the length token we're pointing at, so we can adjust the physical -  // location in the file to point at the last character. -  // -  // FIXME: This won't cope with trigraphs or escaped newlines well. For that, -  // we actually need a preprocessor, which isn't currently available -  // here. Eventually, we'll switch the pointer data of -  // CXSourceLocation/CXSourceRange to a translation unit (CXXUnit), so that the -  // preprocessor will be available here. At that point, we can use -  // Preprocessor::getLocForEndOfToken(). -  if (InstLoc.isValid()) { -    unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, LangOpts); +  if (!EndLoc.isInvalid() && EndLoc.isFileID()) { +    unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);      EndLoc = EndLoc.getFileLocWithOffset(Length);    } @@ -253,6 +234,10 @@ public:    }    bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); +   +  std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> +    getPreprocessedEntities(); +    bool VisitChildren(CXCursor Parent);    // Declaration visitors @@ -371,6 +356,48 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {    return false;  } +std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> +CursorVisitor::getPreprocessedEntities() { +  PreprocessingRecord &PPRec +    = *TU->getPreprocessor().getPreprocessingRecord(); +   +  bool OnlyLocalDecls +    = !TU->isMainFileAST() && TU->getOnlyLocalDecls(); +   +  // There is no region of interest; we have to walk everything. +  if (RegionOfInterest.isInvalid()) +    return std::make_pair(PPRec.begin(OnlyLocalDecls), +                          PPRec.end(OnlyLocalDecls)); + +  // Find the file in which the region of interest lands. +  SourceManager &SM = TU->getSourceManager(); +  std::pair<FileID, unsigned> Begin +    = SM.getDecomposedInstantiationLoc(RegionOfInterest.getBegin()); +  std::pair<FileID, unsigned> End +    = SM.getDecomposedInstantiationLoc(RegionOfInterest.getEnd()); +   +  // The region of interest spans files; we have to walk everything. +  if (Begin.first != End.first) +    return std::make_pair(PPRec.begin(OnlyLocalDecls), +                          PPRec.end(OnlyLocalDecls)); +     +  ASTUnit::PreprocessedEntitiesByFileMap &ByFileMap +    = TU->getPreprocessedEntitiesByFile(); +  if (ByFileMap.empty()) { +    // Build the mapping from files to sets of preprocessed entities. +    for (PreprocessingRecord::iterator E = PPRec.begin(OnlyLocalDecls), +                                    EEnd = PPRec.end(OnlyLocalDecls); +         E != EEnd; ++E) { +      std::pair<FileID, unsigned> P +        = SM.getDecomposedInstantiationLoc((*E)->getSourceRange().getBegin()); +      ByFileMap[P.first].push_back(*E); +    } +  } + +  return std::make_pair(ByFileMap[Begin.first].begin(),  +                        ByFileMap[Begin.first].end()); +} +  /// \brief Visit the children of the given cursor.  ///  /// \returns true if the visitation should be aborted, false if it @@ -425,11 +452,31 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {          if (Visit(MakeCXCursor(*it, CXXUnit), true))            return true;        } -    } else { -      return VisitDeclContext( -                            CXXUnit->getASTContext().getTranslationUnitDecl()); -    } +    } else if (VisitDeclContext( +                            CXXUnit->getASTContext().getTranslationUnitDecl())) +      return true; +    // Walk the preprocessing record. +    if (CXXUnit->getPreprocessor().getPreprocessingRecord()) { +      // FIXME: Once we have the ability to deserialize a preprocessing record, +      // do so. +      PreprocessingRecord::iterator E, EEnd; +      for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) { +        if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) { +          if (Visit(MakeMacroInstantiationCursor(MI, CXXUnit))) +            return true; +           +          continue; +        } +         +        if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) { +          if (Visit(MakeMacroDefinitionCursor(MD, CXXUnit))) +            return true; +           +          continue; +        } +      } +    }      return false;    } @@ -601,9 +648,10 @@ bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) {  }  bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { -  if (Visit(MakeCursorObjCClassRef(D->getCategoryDecl()->getClassInterface(), -                                   D->getLocation(), TU))) -    return true; +  // 'ID' could be null when dealing with invalid code. +  if (ObjCInterfaceDecl *ID = D->getClassInterface()) +    if (Visit(MakeCursorObjCClassRef(ID, D->getLocation(), TU))) +      return true;    return VisitObjCImplDecl(D);  } @@ -994,7 +1042,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,        Args.push_back(source_filename);      Args.insert(Args.end(), command_line_args,                  command_line_args + num_command_line_args); - +    Args.push_back("-Xclang"); +    Args.push_back("-detailed-preprocessing-record");      unsigned NumErrors = Diags->getNumErrors();  #ifdef USE_CRASHTRACER @@ -1093,6 +1142,9 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,    TemporaryFiles.push_back(DiagnosticsFile);    argv.push_back("-fdiagnostics-binary"); +  argv.push_back("-Xclang"); +  argv.push_back("-detailed-preprocessing-record"); +    // Add the null terminator.    argv.push_back(NULL); @@ -1438,6 +1490,14 @@ CXString clang_getCursorSpelling(CXCursor C) {      return createCXString("");    } +  if (C.kind == CXCursor_MacroInstantiation) +    return createCXString(getCursorMacroInstantiation(C)->getName() +                                                           ->getNameStart()); + +  if (C.kind == CXCursor_MacroDefinition) +    return createCXString(getCursorMacroDefinition(C)->getName() +                                                           ->getNameStart()); +    if (clang_isDeclaration(C.kind))      return getDeclSpelling(getCursorDecl(C)); @@ -1508,6 +1568,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {        return createCXString("UnexposedStmt");    case CXCursor_InvalidFile:        return createCXString("InvalidFile"); +  case CXCursor_InvalidCode: +    return createCXString("InvalidCode");    case CXCursor_NoDeclFound:        return createCXString("NoDeclFound");    case CXCursor_NotImplemented: @@ -1518,8 +1580,14 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {        return createCXString("UnexposedAttr");    case CXCursor_IBActionAttr:        return createCXString("attribute(ibaction)"); -    case CXCursor_IBOutletAttr: -      return createCXString("attribute(iboutlet)"); +  case CXCursor_IBOutletAttr: +     return createCXString("attribute(iboutlet)"); +  case CXCursor_PreprocessingDirective: +    return createCXString("preprocessing directive"); +  case CXCursor_MacroDefinition: +    return createCXString("macro definition"); +  case CXCursor_MacroInstantiation: +    return createCXString("macro instantiation");    }    llvm_unreachable("Unhandled CXCursorKind"); @@ -1590,6 +1658,10 @@ unsigned clang_isTranslationUnit(enum CXCursorKind K) {    return K == CXCursor_TranslationUnit;  } +unsigned clang_isPreprocessing(enum CXCursorKind K) { +  return K >= CXCursor_FirstPreprocessing && K <= CXCursor_LastPreprocessing; +} +    unsigned clang_isUnexposed(enum CXCursorKind K) {    switch (K) {      case CXCursor_UnexposedDecl: @@ -1642,6 +1714,22 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {      return cxloc::translateSourceLocation(getCursorContext(C),                                     getLocationFromExpr(getCursorExpr(C))); +  if (C.kind == CXCursor_PreprocessingDirective) { +    SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin(); +    return cxloc::translateSourceLocation(getCursorContext(C), L); +  } + +  if (C.kind == CXCursor_MacroInstantiation) { +    SourceLocation L +      = cxcursor::getCursorMacroInstantiation(C)->getSourceRange().getBegin(); +    return cxloc::translateSourceLocation(getCursorContext(C), L); +  } + +  if (C.kind == CXCursor_MacroDefinition) { +    SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation(); +    return cxloc::translateSourceLocation(getCursorContext(C), L); +  } +      if (!getCursorDecl(C))      return clang_getNullLocation(); @@ -1693,6 +1781,21 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {      return cxloc::translateSourceRange(getCursorContext(C),                                  getCursorStmt(C)->getSourceRange()); +  if (C.kind == CXCursor_PreprocessingDirective) { +    SourceRange R = cxcursor::getCursorPreprocessingDirective(C); +    return cxloc::translateSourceRange(getCursorContext(C), R); +  } + +  if (C.kind == CXCursor_MacroInstantiation) { +    SourceRange R = cxcursor::getCursorMacroInstantiation(C)->getSourceRange(); +    return cxloc::translateSourceRange(getCursorContext(C), R); +  } + +  if (C.kind == CXCursor_MacroDefinition) { +    SourceRange R = cxcursor::getCursorMacroDefinition(C)->getSourceRange(); +    return cxloc::translateSourceRange(getCursorContext(C), R); +  } +      if (!getCursorDecl(C))      return clang_getNullRange(); @@ -1715,6 +1818,11 @@ CXCursor clang_getCursorReferenced(CXCursor C) {      return clang_getNullCursor();    } +  if (C.kind == CXCursor_MacroInstantiation) { +    if (MacroDefinition *Def = getCursorMacroInstantiation(C)->getDefinition()) +      return MakeMacroDefinitionCursor(Def, CXXUnit); +  } +    if (!clang_isReference(C.kind))      return clang_getNullCursor(); @@ -1753,6 +1861,9 @@ CXCursor clang_getCursorDefinition(CXCursor C) {      WasReference = true;    } +  if (C.kind == CXCursor_MacroInstantiation) +    return clang_getCursorReferenced(C); +    if (!clang_isDeclaration(C.kind))      return clang_getNullCursor(); @@ -2101,6 +2212,8 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,    bool Invalid = false;    llvm::StringRef Buffer      = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid); +  if (Invalid) +    return;    Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),              CXXUnit->getASTContext().getLangOptions(), @@ -2188,6 +2301,8 @@ enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,        return CXChildVisit_Recurse;      // Okay: we can annotate the location of this expression +  } else if (clang_isPreprocessing(cursor.kind)) { +    // We can always annotate a preprocessing directive/macro instantiation.    } else {      // Nothing to annotate      return CXChildVisit_Recurse; @@ -2214,31 +2329,94 @@ void clang_annotateTokens(CXTranslationUnit TU,    ASTUnit::ConcurrencyCheck Check(*CXXUnit); -  // Annotate all of the source locations in the region of interest that map +  // Determine the region of interest, which contains all of the tokens.    SourceRange RegionOfInterest;    RegionOfInterest.setBegin(          cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));    SourceLocation End -    = cxloc::translateSourceLocation(clang_getTokenLocation(TU, -                                                     Tokens[NumTokens - 1])); +  = cxloc::translateSourceLocation(clang_getTokenLocation(TU, +                                                        Tokens[NumTokens - 1]));    RegionOfInterest.setEnd(CXXUnit->getPreprocessor().getLocForEndOfToken(End)); -  // FIXME: Would be great to have a "hint" cursor, then walk from that -  // hint cursor upward until we find a cursor whose source range encloses -  // the region of interest, rather than starting from the translation unit. + +  // A mapping from the source locations found when re-lexing or traversing the +  // region of interest to the corresponding cursors.    AnnotateTokensData Annotated; + +  // Relex the tokens within the source range to look for preprocessing  +  // directives. +  SourceManager &SourceMgr = CXXUnit->getSourceManager(); +  std::pair<FileID, unsigned> BeginLocInfo +    = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin()); +  std::pair<FileID, unsigned> EndLocInfo +    = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd()); +   +  llvm::StringRef Buffer; +  bool Invalid = false; +  if (BeginLocInfo.first == EndLocInfo.first && +      ((Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid)),true) && +      !Invalid) { +    Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), +              CXXUnit->getASTContext().getLangOptions(), +              Buffer.begin(), Buffer.data() + BeginLocInfo.second,  +              Buffer.end()); +    Lex.SetCommentRetentionState(true); +     +    // Lex tokens in raw mode until we hit the end of the range, to avoid  +    // entering #includes or expanding macros. +    while (true) { +      Token Tok; +      Lex.LexFromRawLexer(Tok); +       +    reprocess: +      if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { +        // We have found a preprocessing directive. Gobble it up so that we +        // don't see it while preprocessing these tokens later, but keep track of +        // all of the token locations inside this preprocessing directive so that +        // we can annotate them appropriately. +        // +        // FIXME: Some simple tests here could identify macro definitions and +        // #undefs, to provide specific cursor kinds for those. +        std::vector<SourceLocation> Locations; +        do { +          Locations.push_back(Tok.getLocation()); +          Lex.LexFromRawLexer(Tok);         +        } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof)); +         +        using namespace cxcursor; +        CXCursor Cursor +          = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(), +                                                         Locations.back()), +                                             CXXUnit); +        for (unsigned I = 0, N = Locations.size(); I != N; ++I) { +          Annotated[Locations[I].getRawEncoding()] = Cursor; +        } +         +        if (Tok.isAtStartOfLine()) +          goto reprocess; +         +        continue; +      } +       +      if (Tok.is(tok::eof)) +        break; +    } +  } +   +  // Annotate all of the source locations in the region of interest that map to +  // a specific cursor.      CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit);    CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated,                              Decl::MaxPCHLevel, RegionOfInterest);    AnnotateVis.VisitChildren(Parent); - +      for (unsigned I = 0; I != NumTokens; ++I) {      // Determine whether we saw a cursor at this token's location.      AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);      if (Pos == Annotated.end())        continue; - +          Cursors[I] = Pos->second; -  } +  }    }  void clang_disposeTokens(CXTranslationUnit TU, @@ -2254,6 +2432,9 @@ void clang_disposeTokens(CXTranslationUnit TU,  extern "C" {  CXLinkageKind clang_getCursorLinkage(CXCursor cursor) { +  if (!clang_isDeclaration(cursor.kind)) +    return CXLinkage_Invalid; +    Decl *D = cxcursor::getCursorDecl(cursor);    if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))      switch (ND->getLinkage()) {  | 
