CIndexHigh.cpp revision b1ba0efc3d1dc1daa5d82c40bc504e1f368c4fa0
1//===- CIndexHigh.cpp - Higher level API functions ------------------------===// 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#include "CursorVisitor.h" 11#include "CLog.h" 12#include "CXCursor.h" 13#include "CXSourceLocation.h" 14#include "CXTranslationUnit.h" 15#include "clang/AST/DeclObjC.h" 16#include "clang/Frontend/ASTUnit.h" 17#include "llvm/Support/Compiler.h" 18 19using namespace clang; 20using namespace cxcursor; 21using namespace cxindex; 22 23static void getTopOverriddenMethods(CXTranslationUnit TU, 24 Decl *D, 25 SmallVectorImpl<Decl *> &Methods) { 26 if (!D) 27 return; 28 if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D)) 29 return; 30 31 SmallVector<CXCursor, 8> Overridden; 32 cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden); 33 34 if (Overridden.empty()) { 35 Methods.push_back(D->getCanonicalDecl()); 36 return; 37 } 38 39 for (SmallVector<CXCursor, 8>::iterator 40 I = Overridden.begin(), E = Overridden.end(); I != E; ++I) 41 getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods); 42} 43 44namespace { 45 46struct FindFileIdRefVisitData { 47 CXTranslationUnit TU; 48 FileID FID; 49 Decl *Dcl; 50 int SelectorIdIdx; 51 CXCursorAndRangeVisitor visitor; 52 53 typedef SmallVector<Decl *, 8> TopMethodsTy; 54 TopMethodsTy TopMethods; 55 56 FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID, 57 Decl *D, int selectorIdIdx, 58 CXCursorAndRangeVisitor visitor) 59 : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) { 60 Dcl = getCanonical(D); 61 getTopOverriddenMethods(TU, Dcl, TopMethods); 62 } 63 64 ASTContext &getASTContext() const { 65 return static_cast<ASTUnit *>(TU->TUData)->getASTContext(); 66 } 67 68 /// \brief We are looking to find all semantically relevant identifiers, 69 /// so the definition of "canonical" here is different than in the AST, e.g. 70 /// 71 /// \code 72 /// class C { 73 /// C() {} 74 /// }; 75 /// \endcode 76 /// 77 /// we consider the canonical decl of the constructor decl to be the class 78 /// itself, so both 'C' can be highlighted. 79 Decl *getCanonical(Decl *D) const { 80 if (!D) 81 return 0; 82 83 D = D->getCanonicalDecl(); 84 85 if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) { 86 if (ImplD->getClassInterface()) 87 return getCanonical(ImplD->getClassInterface()); 88 89 } else if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D)) { 90 return getCanonical(CXXCtorD->getParent()); 91 } 92 93 return D; 94 } 95 96 bool isHit(Decl *D) const { 97 if (!D) 98 return false; 99 100 D = getCanonical(D); 101 if (D == Dcl) 102 return true; 103 104 if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D)) 105 return isOverriddingMethod(D); 106 107 return false; 108 } 109 110private: 111 bool isOverriddingMethod(Decl *D) const { 112 if (std::find(TopMethods.begin(), TopMethods.end(), D) != 113 TopMethods.end()) 114 return true; 115 116 TopMethodsTy methods; 117 getTopOverriddenMethods(TU, D, methods); 118 for (TopMethodsTy::iterator 119 I = methods.begin(), E = methods.end(); I != E; ++I) { 120 if (std::find(TopMethods.begin(), TopMethods.end(), *I) != 121 TopMethods.end()) 122 return true; 123 } 124 125 return false; 126 } 127}; 128 129} // end anonymous namespace. 130 131/// \brief For a macro \arg Loc, returns the file spelling location and sets 132/// to \arg isMacroArg whether the spelling resides inside a macro definition or 133/// a macro argument. 134static SourceLocation getFileSpellingLoc(SourceManager &SM, 135 SourceLocation Loc, 136 bool &isMacroArg) { 137 assert(Loc.isMacroID()); 138 SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc); 139 if (SpellLoc.isMacroID()) 140 return getFileSpellingLoc(SM, SpellLoc, isMacroArg); 141 142 isMacroArg = SM.isMacroArgExpansion(Loc); 143 return SpellLoc; 144} 145 146static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor, 147 CXCursor parent, 148 CXClientData client_data) { 149 CXCursor declCursor = clang_getCursorReferenced(cursor); 150 if (!clang_isDeclaration(declCursor.kind)) 151 return CXChildVisit_Recurse; 152 153 Decl *D = cxcursor::getCursorDecl(declCursor); 154 if (!D) 155 return CXChildVisit_Continue; 156 157 FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data; 158 if (data->isHit(D)) { 159 cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor); 160 161 // We are looking for identifiers to highlight so for objc methods (and 162 // not a parameter) we can only highlight the selector identifiers. 163 if ((cursor.kind == CXCursor_ObjCClassMethodDecl || 164 cursor.kind == CXCursor_ObjCInstanceMethodDecl) && 165 cxcursor::getSelectorIdentifierIndex(cursor) == -1) 166 return CXChildVisit_Recurse; 167 168 if (clang_isExpression(cursor.kind)) { 169 if (cursor.kind == CXCursor_DeclRefExpr || 170 cursor.kind == CXCursor_MemberRefExpr) { 171 // continue.. 172 173 } else if (cursor.kind == CXCursor_ObjCMessageExpr && 174 cxcursor::getSelectorIdentifierIndex(cursor) != -1) { 175 // continue.. 176 177 } else 178 return CXChildVisit_Recurse; 179 } 180 181 SourceLocation 182 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); 183 SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor); 184 if (SelIdLoc.isValid()) 185 Loc = SelIdLoc; 186 187 ASTContext &Ctx = data->getASTContext(); 188 SourceManager &SM = Ctx.getSourceManager(); 189 bool isInMacroDef = false; 190 if (Loc.isMacroID()) { 191 bool isMacroArg; 192 Loc = getFileSpellingLoc(SM, Loc, isMacroArg); 193 isInMacroDef = !isMacroArg; 194 } 195 196 // We are looking for identifiers in a specific file. 197 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 198 if (LocInfo.first != data->FID) 199 return CXChildVisit_Recurse; 200 201 if (isInMacroDef) { 202 // FIXME: For a macro definition make sure that all expansions 203 // of it expand to the same reference before allowing to point to it. 204 return CXChildVisit_Recurse; 205 } 206 207 data->visitor.visit(data->visitor.context, cursor, 208 cxloc::translateSourceRange(Ctx, Loc)); 209 } 210 return CXChildVisit_Recurse; 211} 212 213static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor, 214 const FileEntry *File, 215 CXCursorAndRangeVisitor Visitor) { 216 assert(clang_isDeclaration(declCursor.kind)); 217 ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData); 218 SourceManager &SM = Unit->getSourceManager(); 219 220 FileID FID = SM.translateFile(File); 221 Decl *Dcl = cxcursor::getCursorDecl(declCursor); 222 if (!Dcl) 223 return; 224 225 FindFileIdRefVisitData data(TU, FID, Dcl, 226 cxcursor::getSelectorIdentifierIndex(declCursor), 227 Visitor); 228 229 if (DeclContext *DC = Dcl->getParentFunctionOrMethod()) { 230 clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU), 231 findFileIdRefVisit, &data); 232 return; 233 } 234 235 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); 236 CursorVisitor FindIdRefsVisitor(TU, 237 findFileIdRefVisit, &data, 238 /*VisitPreprocessorLast=*/true, 239 /*VisitIncludedEntities=*/false, 240 Range, 241 /*VisitDeclsOnly=*/true); 242 FindIdRefsVisitor.visitFileRegion(); 243} 244 245namespace { 246 247struct FindFileMacroRefVisitData { 248 ASTUnit &Unit; 249 const FileEntry *File; 250 const IdentifierInfo *Macro; 251 CXCursorAndRangeVisitor visitor; 252 253 FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File, 254 const IdentifierInfo *Macro, 255 CXCursorAndRangeVisitor visitor) 256 : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { } 257 258 ASTContext &getASTContext() const { 259 return Unit.getASTContext(); 260 } 261}; 262 263} // anonymous namespace 264 265static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor, 266 CXCursor parent, 267 CXClientData client_data) { 268 const IdentifierInfo *Macro = 0; 269 if (cursor.kind == CXCursor_MacroDefinition) 270 Macro = getCursorMacroDefinition(cursor)->getName(); 271 else if (cursor.kind == CXCursor_MacroExpansion) 272 Macro = getCursorMacroExpansion(cursor).getName(); 273 if (!Macro) 274 return CXChildVisit_Continue; 275 276 FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data; 277 if (data->Macro != Macro) 278 return CXChildVisit_Continue; 279 280 SourceLocation 281 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); 282 283 ASTContext &Ctx = data->getASTContext(); 284 SourceManager &SM = Ctx.getSourceManager(); 285 bool isInMacroDef = false; 286 if (Loc.isMacroID()) { 287 bool isMacroArg; 288 Loc = getFileSpellingLoc(SM, Loc, isMacroArg); 289 isInMacroDef = !isMacroArg; 290 } 291 292 // We are looking for identifiers in a specific file. 293 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 294 if (SM.getFileEntryForID(LocInfo.first) != data->File) 295 return CXChildVisit_Continue; 296 297 if (isInMacroDef) { 298 // FIXME: For a macro definition make sure that all expansions 299 // of it expand to the same reference before allowing to point to it. 300 return CXChildVisit_Continue; 301 } 302 303 data->visitor.visit(data->visitor.context, cursor, 304 cxloc::translateSourceRange(Ctx, Loc)); 305 return CXChildVisit_Continue; 306} 307 308static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor, 309 const FileEntry *File, 310 CXCursorAndRangeVisitor Visitor) { 311 if (Cursor.kind != CXCursor_MacroDefinition && 312 Cursor.kind != CXCursor_MacroExpansion) 313 return; 314 315 ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData); 316 SourceManager &SM = Unit->getSourceManager(); 317 318 FileID FID = SM.translateFile(File); 319 const IdentifierInfo *Macro = 0; 320 if (Cursor.kind == CXCursor_MacroDefinition) 321 Macro = getCursorMacroDefinition(Cursor)->getName(); 322 else 323 Macro = getCursorMacroExpansion(Cursor).getName(); 324 if (!Macro) 325 return; 326 327 FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor); 328 329 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); 330 CursorVisitor FindMacroRefsVisitor(TU, 331 findFileMacroRefVisit, &data, 332 /*VisitPreprocessorLast=*/false, 333 /*VisitIncludedEntities=*/false, 334 Range); 335 FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion(); 336} 337 338 339//===----------------------------------------------------------------------===// 340// libclang public APIs. 341//===----------------------------------------------------------------------===// 342 343extern "C" { 344 345void clang_findReferencesInFile(CXCursor cursor, CXFile file, 346 CXCursorAndRangeVisitor visitor) { 347 LogRef Log = Logger::make(LLVM_FUNCTION_NAME); 348 349 if (clang_Cursor_isNull(cursor)) { 350 if (Log) 351 *Log << "Null cursor"; 352 return; 353 } 354 if (cursor.kind == CXCursor_NoDeclFound) { 355 if (Log) 356 *Log << "Got CXCursor_NoDeclFound"; 357 return; 358 } 359 if (!file) { 360 if (Log) 361 *Log << "Null file"; 362 return; 363 } 364 if (!visitor.visit) { 365 if (Log) 366 *Log << "Null visitor"; 367 return; 368 } 369 370 ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor); 371 if (!CXXUnit) 372 return; 373 374 ASTUnit::ConcurrencyCheck Check(*CXXUnit); 375 376 if (cursor.kind == CXCursor_MacroDefinition || 377 cursor.kind == CXCursor_MacroExpansion) { 378 findMacroRefsInFile(cxcursor::getCursorTU(cursor), 379 cursor, 380 static_cast<const FileEntry *>(file), 381 visitor); 382 return; 383 } 384 385 // We are interested in semantics of identifiers so for C++ constructor exprs 386 // prefer type references, e.g.: 387 // 388 // return MyStruct(); 389 // 390 // for 'MyStruct' we'll have a cursor pointing at the constructor decl but 391 // we are actually interested in the type declaration. 392 cursor = cxcursor::getTypeRefCursor(cursor); 393 394 CXCursor refCursor = clang_getCursorReferenced(cursor); 395 396 if (!clang_isDeclaration(refCursor.kind)) { 397 if (Log) 398 *Log << "cursor is not referencing a declaration"; 399 return; 400 } 401 402 findIdRefsInFile(cxcursor::getCursorTU(cursor), 403 refCursor, 404 static_cast<const FileEntry *>(file), 405 visitor); 406} 407 408static enum CXVisitorResult _visitCursorAndRange(void *context, 409 CXCursor cursor, 410 CXSourceRange range) { 411 CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context; 412 return INVOKE_BLOCK2(block, cursor, range); 413} 414 415void clang_findReferencesInFileWithBlock(CXCursor cursor, 416 CXFile file, 417 CXCursorAndRangeVisitorBlock block) { 418 CXCursorAndRangeVisitor visitor = { block, 419 block ? _visitCursorAndRange : 0 }; 420 return clang_findReferencesInFile(cursor, file, visitor); 421} 422 423} // end: extern "C" 424 425