CXCursor cxcursor::MakeCXCursor(const Decl *D, CXTranslationUnit TU, SourceRange RegionOfInterest, bool FirstInDeclGroup) { assert(D && TU && "Invalid arguments!"); CXCursorKind K = getCursorKindForDecl(D); if (K == CXCursor_ObjCClassMethodDecl || K == CXCursor_ObjCInstanceMethodDecl) { int SelectorIdIndex = -1; // Check if cursor points to a selector id. if (RegionOfInterest.isValid() && RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) { SmallVector<SourceLocation, 16> SelLocs; cast<ObjCMethodDecl>(D)->getSelectorLocs(SelLocs); SmallVectorImpl<SourceLocation>::iterator I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin()); if (I != SelLocs.end()) SelectorIdIndex = I - SelLocs.begin(); } CXCursor C = { K, SelectorIdIndex, { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }}; return C; } CXCursor C = { K, 0, { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }}; return C; }
void RemoveUnusedStructField::removeOneInitExpr(const Expr *E) { TransAssert(NumFields && "NumFields cannot be zero!"); SourceRange ExpRange = E->getSourceRange(); SourceLocation StartLoc = ExpRange.getBegin(); SourceLocation EndLoc = ExpRange.getEnd(); if (NumFields == 1) { // The last field can optionally have a trailing comma // If this is the only field also the comma has to be removed SourceLocation NewEndLoc = RewriteHelper->getEndLocationUntil(ExpRange, '}'); NewEndLoc = NewEndLoc.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(StartLoc, NewEndLoc)); return; } else if (IsFirstField) { EndLoc = RewriteHelper->getEndLocationUntil(ExpRange, ','); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); return; } const char *Buf = SrcManager->getCharacterData(StartLoc); int Offset = 0; while (*Buf != ',') { Buf--; Offset--; } StartLoc = StartLoc.getLocWithOffset(Offset); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); }
static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures, const IdentifierNamingCheck::NamingCheckId &Decl, SourceRange Range, SourceManager *SourceMgr = nullptr) { // Do nothing if the provided range is invalid. if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid()) return; // If we have a source manager, use it to convert to the spelling location for // performing the fix. This is necessary because macros can map the same // spelling location to different source locations, and we only want to fix // the token once, before it is expanded by the macro. SourceLocation FixLocation = Range.getBegin(); if (SourceMgr) FixLocation = SourceMgr->getSpellingLoc(FixLocation); if (FixLocation.isInvalid()) return; // Try to insert the identifier location in the Usages map, and bail out if it // is already in there auto &Failure = Failures[Decl]; if (!Failure.RawUsageLocs.insert(FixLocation.getRawEncoding()).second) return; if (!Failure.ShouldFix) return; // Check if the range is entirely contained within a macro argument. SourceLocation MacroArgExpansionStartForRangeBegin; SourceLocation MacroArgExpansionStartForRangeEnd; bool RangeIsEntirelyWithinMacroArgument = SourceMgr && SourceMgr->isMacroArgExpansion(Range.getBegin(), &MacroArgExpansionStartForRangeBegin) && SourceMgr->isMacroArgExpansion(Range.getEnd(), &MacroArgExpansionStartForRangeEnd) && MacroArgExpansionStartForRangeBegin == MacroArgExpansionStartForRangeEnd; // Check if the range contains any locations from a macro expansion. bool RangeContainsMacroExpansion = RangeIsEntirelyWithinMacroArgument || Range.getBegin().isMacroID() || Range.getEnd().isMacroID(); bool RangeCanBeFixed = RangeIsEntirelyWithinMacroArgument || !RangeContainsMacroExpansion; Failure.ShouldFix = RangeCanBeFixed; }
CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range, CXTranslationUnit TU) { CXCursor C = { CXCursor_PreprocessingDirective, { reinterpret_cast<void *>(Range.getBegin().getRawEncoding()), reinterpret_cast<void *>(Range.getEnd().getRawEncoding()), TU } }; return C; }
CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range, CXTranslationUnit TU) { CXCursor C = { CXCursor_PreprocessingDirective, 0, { Range.getBegin().getPtrEncoding(), Range.getEnd().getPtrEncoding(), TU } }; return C; }
static Optional<bool> comparePiece(const PathDiagnosticPiece &X, const PathDiagnosticPiece &Y) { if (X.getKind() != Y.getKind()) return X.getKind() < Y.getKind(); FullSourceLoc XL = X.getLocation().asLocation(); FullSourceLoc YL = Y.getLocation().asLocation(); if (XL != YL) return XL.isBeforeInTranslationUnitThan(YL); if (X.getString() != Y.getString()) return X.getString() < Y.getString(); if (X.getRanges().size() != Y.getRanges().size()) return X.getRanges().size() < Y.getRanges().size(); const SourceManager &SM = XL.getManager(); for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { SourceRange XR = X.getRanges()[i]; SourceRange YR = Y.getRanges()[i]; if (XR != YR) { if (XR.getBegin() != YR.getBegin()) return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); } } switch (X.getKind()) { case PathDiagnosticPiece::ControlFlow: return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), cast<PathDiagnosticControlFlowPiece>(Y)); case PathDiagnosticPiece::Event: case PathDiagnosticPiece::Note: return None; case PathDiagnosticPiece::Macro: return compareMacro(cast<PathDiagnosticMacroPiece>(X), cast<PathDiagnosticMacroPiece>(Y)); case PathDiagnosticPiece::Call: return compareCall(cast<PathDiagnosticCallPiece>(X), cast<PathDiagnosticCallPiece>(Y)); } llvm_unreachable("all cases handled"); }
int getNumberOfLines(SourceRange sourceRange) { SourceLocation startLocation = sourceRange.getBegin(); SourceLocation endLocation = sourceRange.getEnd(); SourceManager *sourceManager = &_carrier->astContext()->getSourceManager(); unsigned startLineNumber = sourceManager->getPresumedLineNumber(startLocation); unsigned endLineNumber = sourceManager->getPresumedLineNumber(endLocation); return endLineNumber - startLineNumber + 1; }
void StmtDumper::DumpSourceRange(const Stmt *Node) { // Can't translate locations if a SourceManager isn't available. if (SM == 0) return; // TODO: If the parent expression is available, we can print a delta vs its // location. SourceRange R = Node->getSourceRange(); OS << " <"; DumpLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { OS << ", "; DumpLocation(R.getEnd()); } OS << ">"; // <t2.c:123:421[blah], t2.c:412:321> }
/// \brief Obtain the original source code text from a SourceRange. static StringRef getStringFromRange(SourceManager &SourceMgr, const LangOptions &LangOpts, SourceRange Range) { if (SourceMgr.getFileID(Range.getBegin()) != SourceMgr.getFileID(Range.getEnd())) return NULL; CharSourceRange SourceChars(Range, true); return Lexer::getSourceText(SourceChars, SourceMgr, LangOpts); }
void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) { if (!V) { SubExprs[CONDVAR] = 0; return; } SourceRange VarRange = V->getSourceRange(); SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); }
std::string SynthesizeRemovalConsumer::range(SourceRange R) { std::string src; llvm::raw_string_ostream sst(src); sst << "("; R.getBegin().print(sst, astContext->getSourceManager()); sst << ", "; R.getEnd().print(sst, astContext->getSourceManager()); sst << ")"; return sst.str(); }
/// getRewrittenText - Return the rewritten form of the text in the specified /// range. If the start or end of the range was unrewritable or if they are /// in different buffers, this returns an empty string. /// /// Note that this method is not particularly efficient. /// std::string Rewriter::getRewrittenText(SourceRange Range) const { if (!isRewritable(Range.getBegin()) || !isRewritable(Range.getEnd())) return ""; FileID StartFileID, EndFileID; unsigned StartOff, EndOff; StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); if (StartFileID != EndFileID) return ""; // Start and end in different buffers. // If edits have been made to this buffer, the delta between the range may // have changed. std::map<FileID, RewriteBuffer>::const_iterator I = RewriteBuffers.find(StartFileID); if (I == RewriteBuffers.end()) { // If the buffer hasn't been rewritten, just return the text from the input. const char *Ptr = SourceMgr->getCharacterData(Range.getBegin()); // Adjust the end offset to the end of the last token, instead of being the // start of the last token. EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); return std::string(Ptr, Ptr+EndOff-StartOff); } const RewriteBuffer &RB = I->second; EndOff = RB.getMappedOffset(EndOff, true); StartOff = RB.getMappedOffset(StartOff); // Adjust the end offset to the end of the last token, instead of being the // start of the last token. EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); // Advance the iterators to the right spot, yay for linear time algorithms. RewriteBuffer::iterator Start = RB.begin(); std::advance(Start, StartOff); RewriteBuffer::iterator End = Start; std::advance(End, EndOff-StartOff); return std::string(Start, End); }
void WhileStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { if (!V) { SubExprs[VAR] = nullptr; return; } SourceRange VarRange = V->getSourceRange(); SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); }
bool RewriteUtils::removeVarFromDeclStmt(DeclStmt *DS, const VarDecl *VD, Decl *PrevDecl, bool IsFirstDecl) { SourceRange StmtRange = DS->getSourceRange(); // VD is the the only declaration, so it is safe to remove the entire stmt if (DS->isSingleDecl()) { return !(TheRewriter->RemoveText(StmtRange)); } // handle the case where we could have implicit declaration of RecordDecl // e.g., // foo (void) { // struct S0 *s; // ...; // } // in this case, struct S0 is implicitly declared if (PrevDecl) { if ( RecordDecl *RD = dyn_cast<RecordDecl>(PrevDecl) ) { DeclGroup DGroup = DS->getDeclGroup().getDeclGroup(); IsFirstDecl = true; if (!RD->getDefinition() && DGroup.size() == 2) return !(TheRewriter->RemoveText(StmtRange)); } } SourceRange VarRange = VD->getSourceRange(); // VD is the first declaration in a declaration group. // We keep the leading type string if (IsFirstDecl) { // We need to get the outermost TypeLocEnd instead of the StartLoc of // a var name, because we need to handle the case below: // int *x, *y; // If we rely on the StartLoc of a var name, then we will make bad // transformation like: // int * *y; SourceLocation NewStartLoc = getVarDeclTypeLocEnd(VD); SourceLocation NewEndLoc = getEndLocationUntil(VarRange, ','); return !(TheRewriter->RemoveText(SourceRange(NewStartLoc, NewEndLoc))); } TransAssert(PrevDecl && "PrevDecl cannot be NULL!"); SourceLocation VarEndLoc = VarRange.getEnd(); SourceRange PrevDeclRange = PrevDecl->getSourceRange(); SourceLocation PrevDeclEndLoc = getEndLocationUntil(PrevDeclRange, ','); return !(TheRewriter->RemoveText(SourceRange(PrevDeclEndLoc, VarEndLoc))); }
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, const CGFunctionInfo &FnInfo) { const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); // Check if we should generate debug info for this function. if (CGM.getModuleDebugInfo() && !FD->hasAttr<NoDebugAttr>()) DebugInfo = CGM.getModuleDebugInfo(); FunctionArgList Args; QualType ResTy = FD->getResultType(); CurGD = GD; if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance()) CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args); for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) Args.push_back(FD->getParamDecl(i)); SourceRange BodyRange; if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); // Emit the standard function prologue. StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin()); // Generate the body of the function. if (isa<CXXDestructorDecl>(FD)) EmitDestructorBody(Args); else if (isa<CXXConstructorDecl>(FD)) EmitConstructorBody(Args); else if (getContext().getLangOpts().CUDA && !CGM.getCodeGenOpts().CUDAIsDevice && FD->hasAttr<CUDAGlobalAttr>()) CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args); else if (isa<CXXConversionDecl>(FD) && cast<CXXConversionDecl>(FD)->isLambdaToBlockPointerConversion()) { // The lambda conversion to block pointer is special; the semantics can't be // expressed in the AST, so IRGen needs to special-case it. EmitLambdaToBlockPointerBody(Args); } else if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) { // The lambda "__invoke" function is special, because it forwards or // clones the body of the function call operator (but is actually static). EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD)); } else EmitFunctionBody(Args); // Emit the standard function epilogue. FinishFunction(BodyRange.getEnd()); // If we haven't marked the function nothrow through other means, do // a quick pass now to see if we can. if (!CurFn->doesNotThrow()) TryMarkNoThrow(CurFn); }
void WhitespaceManager::storeReplacement(const SourceRange &Range, StringRef Text) { unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) - SourceMgr.getFileOffset(Range.getBegin()); // Don't create a replacement, if it does not change anything. if (StringRef(SourceMgr.getCharacterData(Range.getBegin()), WhitespaceLength) == Text) return; Replaces.insert(tooling::Replacement( SourceMgr, CharSourceRange::getCharRange(Range), Text)); }
bool RewriteUtils::removeVarInitExpr(const VarDecl *VD) { TransAssert(VD->hasInit() && "VarDecl doesn't have an Init Expr!"); SourceLocation NameStartLoc = VD->getLocation(); SourceLocation InitStartLoc = getLocationUntil(NameStartLoc, '='); const Expr *Init = VD->getInit(); SourceRange ExprRange = Init->getSourceRange(); SourceLocation InitEndLoc = ExprRange.getEnd(); return !TheRewriter->RemoveText(SourceRange(InitStartLoc, InitEndLoc)); }
bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) const { if (range.isInvalid()) return false; ListTy::const_iterator I = List.begin(); while (I != List.end()) { FullSourceLoc diagLoc = I->getLocation(); if ((IDs.empty() || // empty means any diagnostic in the range. std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && (diagLoc == range.getEnd() || diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { return true; } ++I; } return false; }
/* We print this in a format that Python can easily understand and parse */ void PrintFunctionInfo(const FunctionDecl *fd) { SourceRange sr = fd->getSourceRange(); PresumedLoc begin = sm->getPresumedLoc(sr.getBegin()); PresumedLoc end = sm->getPresumedLoc(sr.getEnd()); std::cout << "{'function': '" << fd->getDeclName().getAsString() << "'"; std::cout << ", 'file': '" << begin.getFilename() << "'"; std::cout << ", 'begin': [" << begin.getLine() << ", " << begin.getColumn() << "]"; std::cout << ", 'end': [" << end.getLine() << ", " << end.getColumn() << "]"; std::cout << "}" << std::endl; }
/// HandleComment - Hook into the preprocessor and extract comments containing /// expected errors and warnings. bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, SourceRange Comment) { SourceManager &SM = PP.getSourceManager(); // If this comment is for a different source manager, ignore it. if (SrcManager && &SM != SrcManager) return false; SourceLocation CommentBegin = Comment.getBegin(); const char *CommentRaw = SM.getCharacterData(CommentBegin); StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw); if (C.empty()) return false; // Fold any "\<EOL>" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { ParseDirective(C, &ED, SM, &PP, CommentBegin, Status, *Markers); return false; } std::string C2; C2.reserve(C.size()); for (size_t last = 0;; loc = C.find('\\', last)) { if (loc == StringRef::npos || loc == C.size()) { C2 += C.substr(last); break; } C2 += C.substr(last, loc-last); last = loc + 1; if (C[last] == '\n' || C[last] == '\r') { ++last; // Escape \r\n or \n\r, but not \n\n. if (last < C.size()) if (C[last] == '\n' || C[last] == '\r') if (C[last] != C[last-1]) ++last; } else { // This was just a normal backslash. C2 += '\\'; } } if (!C2.empty()) ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status, *Markers); return false; }
bool RemoveUnusedFunction::hasAtLeastOneValidLocation(const FunctionDecl *FD) { for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(), RE = FD->redecls_end(); RI != RE; ++RI) { SourceRange FuncRange = FD->getSourceRange(); SourceLocation StartLoc = FuncRange.getBegin(); SourceLocation EndLoc = FuncRange.getEnd(); if (SrcManager->isWrittenInMainFile(StartLoc) && SrcManager->isWrittenInMainFile(EndLoc)) return true; } return false; }
bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { if (!isRewritable(range.getBegin())) return true; if (!isRewritable(range.getEnd())) return true; if (replacementRange.isInvalid()) return true; SourceLocation start = range.getBegin(); unsigned origLength = getRangeSize(range); unsigned newLength = getRangeSize(replacementRange); FileID FID; unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), FID); StringRef MB = SourceMgr->getBufferData(FID); return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); }
/// HandleComment - Hook into the preprocessor and extract comments containing /// expected errors and warnings. bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, SourceRange Comment) { SourceManager &SM = PP.getSourceManager(); SourceLocation CommentBegin = Comment.getBegin(); const char *CommentRaw = SM.getCharacterData(CommentBegin); StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw); if (C.empty()) return false; // Fold any "\<EOL>" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { if (ParseDirective(C, ED, SM, CommentBegin, PP.getDiagnostics())) if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(CommentBegin))) FilesWithDirectives.insert(E); return false; } std::string C2; C2.reserve(C.size()); for (size_t last = 0;; loc = C.find('\\', last)) { if (loc == StringRef::npos || loc == C.size()) { C2 += C.substr(last); break; } C2 += C.substr(last, loc-last); last = loc + 1; if (C[last] == '\n' || C[last] == '\r') { ++last; // Escape \r\n or \n\r, but not \n\n. if (last < C.size()) if (C[last] == '\n' || C[last] == '\r') if (C[last] != C[last-1]) ++last; } else { // This was just a normal backslash. C2 += '\\'; } } if (!C2.empty()) if (ParseDirective(C2, ED, SM, CommentBegin, PP.getDiagnostics())) if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(CommentBegin))) FilesWithDirectives.insert(E); return false; }
void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range, const char *HighlightStart, const char *HighlightEnd) { SourceManager &SM = R.getSourceMgr(); const LangOptions &LangOpts = R.getLangOpts(); SourceLocation InstantiationStart = SM.getExpansionLoc(Range.getBegin()); unsigned StartLineNo = SM.getExpansionLineNumber(InstantiationStart); SourceLocation InstantiationEnd = SM.getExpansionLoc(Range.getEnd()); unsigned EndLineNo = SM.getExpansionLineNumber(InstantiationEnd); if (EndLineNo < StartLineNo) return; if (SM.getFileID(InstantiationStart) != BugFileID || SM.getFileID(InstantiationEnd) != BugFileID) return; // Compute the column number of the end. unsigned EndColNo = SM.getExpansionColumnNumber(InstantiationEnd); unsigned OldEndColNo = EndColNo; if (EndColNo) { // Add in the length of the token, so that we cover multi-char tokens. EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1; } // Highlight the range. Make the span tag the outermost tag for the // selected range. SourceLocation E = InstantiationEnd.getLocWithOffset(EndColNo - OldEndColNo); html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd); }
void ReturnVoid::keepFuncDefRange(FunctionDecl *FD) { TransAssert(!FuncDefStartPos && !FuncDefEndPos && "Duplicated function definition?"); SourceRange FuncDefRange = FD->getSourceRange(); SourceLocation StartLoc = FuncDefRange.getBegin(); FuncDefStartPos = SrcManager->getCharacterData(StartLoc); SourceLocation EndLoc = FuncDefRange.getEnd(); FuncDefEndPos = SrcManager->getCharacterData(EndLoc); }
bool RewriteUtils::removeTextUntil(SourceRange Range, char C) { SourceLocation StartLoc = Range.getBegin(); // I don't know the reason, but seems Clang treats the following two // cases differently: // (1) template<bool, typename> // in this case, the RangeSize is 5, which includes the ',' // (2) template<typename, typename> // in this case, the RangeSize is 8, which excludes the comma SourceLocation EndLoc = Range.getEnd(); const char *EndBuf = SrcManager->getCharacterData(EndLoc); if (*EndBuf != C) EndLoc = getEndLocationUntil(Range, C); return !TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc)); }
bool RewriteUtils::removeArraySubscriptExpr(const Expr *E) { SourceRange ERange = E->getSourceRange(); SourceLocation StartLoc = ERange.getBegin(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); int Offset = 0; while (*StartBuf != '[') { StartBuf--; Offset--; } StartLoc = StartLoc.getLocWithOffset(Offset); SourceLocation EndLoc = ERange.getEnd(); EndLoc = getLocationUntil(EndLoc, ']'); return !TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc)); }
int runFD(const FunctionDecl *md, SourceManager &sm) { if (!md->hasBody()) return 0; if (!md->isThisDeclarationADefinition()) return 0; DeclarationNameInfo info = md->getNameInfo(); FullSourceLoc b(md->getLocStart(), sm), _e(md->getLocEnd(), sm); FullSourceLoc e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, *this->lopt), sm); SourceRange nameRange = SourceRange(info.getLoc()); FullSourceLoc d(nameRange.getBegin(), sm), _f(nameRange.getEnd(), sm); FullSourceLoc f(clang::Lexer::getLocForEndOfToken(_f, 0, sm, *this->lopt), sm); string start(sm.getCharacterData(b), sm.getCharacterData(d)-sm.getCharacterData(b)); string name(sm.getCharacterData(d), sm.getCharacterData(f)-sm.getCharacterData(d)); string end(sm.getCharacterData(f), sm.getCharacterData(e)-sm.getCharacterData(f)); if (this->methods.find(name) != this->methods.end()) { message("Redefinition of method " + name); return 1; } METHOD* m = new METHOD(); m->pre = start; m->name = name; m->post = end; getAbsoluteLocation(FullSourceLoc(md->getLocStart(), sm), FullSourceLoc(md->getLocEnd(), sm), &m->location.begin, &m->location.end, *this->lopt); m->sm = &sm; m->range = CharSourceRange:: getTokenRange(SourceRange(info.getLoc())); this->methods[name] = m; // For debugging purposes // cout << start << "|" << name << "|" << end << endl; return 0; }
virtual void run(const MatchFinder::MatchResult &Result) { auto *d = Result.Nodes.getNodeAs<CXXConstructorDecl>("stuff"); if (d) { if (d->getNumCtorInitializers() > 0) { const CXXCtorInitializer *firstinit = *d->init_begin(); if (!firstinit->isWritten()) { llvm::errs() << "firstinit not written; skipping\n"; return; } if (firstinit->isBaseInitializer()) { TypeLoc basetypeloc = firstinit->getBaseClassLoc(); llvm::errs() << "firstinit as base loc: " << basetypeloc.getBeginLoc().printToString( *Result.SourceManager) << "\n"; } SourceLocation initloc = firstinit->getSourceLocation(); llvm::errs() << "firstinit loc: " << initloc.printToString(*Result.SourceManager) << "\n"; SourceRange initrange = firstinit->getSourceRange(); llvm::errs() << "firstinit range from " << initrange.getBegin().printToString( *Result.SourceManager) << "\n"; llvm::errs() << "firstinit range to " << initrange.getEnd().printToString( *Result.SourceManager) << "\n"; SourceLocation start = firstinit->getLParenLoc(); llvm::errs() << "firstinit start: " << start.printToString(*Result.SourceManager) << "\n"; Token tok_id = GetTokenBeforeLocation(start, *Result.Context); llvm::errs() << " tok_id: " << tok_id.getLocation().printToString( *Result.SourceManager) << "\n"; Token tok_colon = GetTokenBeforeLocation(tok_id.getLocation(), *Result.Context); llvm::errs() << " tok_colon: " << tok_colon.getLocation().printToString( *Result.SourceManager) << "\n"; const CXXCtorInitializer *lastinit = *d->init_rbegin(); SourceLocation end = lastinit->getRParenLoc(); llvm::errs() << "lastinit end: " << end.printToString(*Result.SourceManager) << "\n"; //init->getInit()->dump(); } } }
void ReturnBracedInitListCheck::check(const MatchFinder::MatchResult &Result) { const auto *MatchedFunctionDecl = Result.Nodes.getNodeAs<FunctionDecl>("fn"); const auto *MatchedConstructExpr = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor"); // Don't make replacements in macro. SourceLocation Loc = MatchedConstructExpr->getExprLoc(); if (Loc.isMacroID()) return; // Make sure that the return type matches the constructed type. const QualType ReturnType = MatchedFunctionDecl->getReturnType().getCanonicalType(); const QualType ConstructType = MatchedConstructExpr->getType().getCanonicalType(); if (ReturnType != ConstructType) return; auto Diag = diag(Loc, "avoid repeating the return type from the " "declaration; use a braced initializer list instead"); const SourceRange CallParensRange = MatchedConstructExpr->getParenOrBraceRange(); // Make sure there is an explicit constructor call. if (CallParensRange.isInvalid()) return; // Make sure that the ctor arguments match the declaration. for (unsigned I = 0, NumParams = MatchedConstructExpr->getNumArgs(); I < NumParams; ++I) { if (const auto *VD = dyn_cast<VarDecl>( MatchedConstructExpr->getConstructor()->getParamDecl(I))) { if (MatchedConstructExpr->getArg(I)->getType().getCanonicalType() != VD->getType().getCanonicalType()) return; } } // Range for constructor name and opening brace. CharSourceRange CtorCallSourceRange = CharSourceRange::getTokenRange( Loc, CallParensRange.getBegin().getLocWithOffset(-1)); Diag << FixItHint::CreateRemoval(CtorCallSourceRange) << FixItHint::CreateReplacement(CallParensRange.getBegin(), "{") << FixItHint::CreateReplacement(CallParensRange.getEnd(), "}"); }