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