//--------------------------------------------------------- void DocumentXML::addLocationRange(const SourceRange& R) { PresumedLoc PStartLoc = addLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { SourceManager& SM = Ctx->getSourceManager(); SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd()); if (!SpellingLoc.isInvalid()) { PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc); if (PStartLoc.isInvalid() || strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) { addToMap(SourceFiles, PLoc.getFilename(), ID_FILE); addAttribute("endfile", PLoc.getFilename()); addAttribute("endline", PLoc.getLine()); addAttribute("endcol", PLoc.getColumn()); } else if (PLoc.getLine() != PStartLoc.getLine()) { addAttribute("endline", PLoc.getLine()); addAttribute("endcol", PLoc.getColumn()); } else { addAttribute("endcol", PLoc.getColumn()); } } } }
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)); }
std::pair<unsigned, unsigned> PreprocessingRecord::findLocalPreprocessedEntitiesInRange( SourceRange Range) const { if (Range.isInvalid()) return std::make_pair(0,0); assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin()); unsigned End = findEndLocalPreprocessedEntity(Range.getEnd()); return std::make_pair(Begin, End); }
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)); }
/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) /// any characters in LineNo that intersect the SourceRange. void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, SourceManager& SourceMgr, unsigned LineNo, std::string &CaratLine, const std::string &SourceLine) { assert(CaratLine.size() == SourceLine.size() && "Expect a correspondence between source and carat line!"); if (!R.isValid()) return; unsigned StartLineNo = SourceMgr.getLogicalLineNumber(R.getBegin()); if (StartLineNo > LineNo) return; // No intersection. unsigned EndLineNo = SourceMgr.getLogicalLineNumber(R.getEnd()); if (EndLineNo < LineNo) return; // No intersection. // Compute the column number of the start. unsigned StartColNo = 0; if (StartLineNo == LineNo) { StartColNo = SourceMgr.getLogicalColumnNumber(R.getBegin()); if (StartColNo) --StartColNo; // Zero base the col #. } // Pick the first non-whitespace column. while (StartColNo < SourceLine.size() && (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) ++StartColNo; // Compute the column number of the end. unsigned EndColNo = CaratLine.size(); if (EndLineNo == LineNo) { EndColNo = SourceMgr.getLogicalColumnNumber(R.getEnd()); if (EndColNo) { --EndColNo; // Zero base the col #. // Add in the length of the token, so that we cover multi-char tokens. EndColNo += Lexer::MeasureTokenLength(R.getEnd(), SourceMgr); } else { EndColNo = CaratLine.size(); } } // Pick the last non-whitespace column. while (EndColNo-1 && (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) --EndColNo; // Fill the range with ~'s. assert(StartColNo <= EndColNo && "Invalid range!"); for (unsigned i = StartColNo; i != EndColNo; ++i) CaratLine[i] = '~'; }
/// TryStaticMemberPointerUpcast - Tests whether a conversion according to /// C++ 5.2.9p9 is valid: /// /// An rvalue of type "pointer to member of D of type cv1 T" can be /// converted to an rvalue of type "pointer to member of B of type cv2 T", /// where B is a base class of D [...]. /// TryStaticCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange) { const MemberPointerType *SrcMemPtr = SrcType->getAsMemberPointerType(); if (!SrcMemPtr) return TSC_NotApplicable; const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(); if (!DestMemPtr) return TSC_NotApplicable; // T == T, modulo cv if (Self.Context.getCanonicalType( SrcMemPtr->getPointeeType().getUnqualifiedType()) != Self.Context.getCanonicalType(DestMemPtr->getPointeeType(). getUnqualifiedType())) return TSC_NotApplicable; // B base of D QualType SrcClass(SrcMemPtr->getClass(), 0); QualType DestClass(DestMemPtr->getClass(), 0); BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, /*DetectVirtual=*/true); if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) { return TSC_NotApplicable; } // B is a base of D. But is it an allowed base? If not, it's a hard error. if (Paths.isAmbiguous(DestClass)) { Paths.clear(); Paths.setRecordingPaths(true); bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); assert(StillOkay); StillOkay = StillOkay; std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths); Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv) << 1 << SrcClass << DestClass << PathDisplayStr << OpRange; return TSC_Failed; } if (const RecordType *VBase = Paths.getDetectedVirtual()) { Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual) << SrcClass << DestClass << QualType(VBase, 0) << OpRange; return TSC_Failed; } // FIXME: Test accessibility. return TSC_Success; }
/// \brief Get a StringRef representing a SourceRange. static StringRef getAsString(const MatchFinder::MatchResult &Result, SourceRange R) { const SourceManager &SM = *Result.SourceManager; // Don't even try to resolve macro or include contraptions. Not worth emitting // a fixit for. if (R.getBegin().isMacroID() || !SM.isWrittenInSameFile(R.getBegin(), R.getEnd())) return StringRef(); const char *Begin = SM.getCharacterData(R.getBegin()); const char *End = SM.getCharacterData(Lexer::getLocForEndOfToken( R.getEnd(), 0, SM, Result.Context->getLangOpts())); return StringRef(Begin, End - Begin); }
void RemoveNamespace::removeLastNamespaceFromUsingDecl( const UsingDirectiveDecl *D, const NamespaceDecl *ND) { SourceLocation IdLocStart = D->getIdentLocation(); SourceRange DeclSourceRange = D->getSourceRange(); SourceLocation DeclLocStart = DeclSourceRange.getBegin(); const char *IdStartBuf = SrcManager->getCharacterData(IdLocStart); const char *DeclStartBuf = SrcManager->getCharacterData(DeclLocStart); unsigned Count = 0; int Offset = 0; while (IdStartBuf != DeclStartBuf) { if (*IdStartBuf != ':') { IdStartBuf--; Offset--; continue; } Count++; if (Count == 2) { break; } Offset--; IdStartBuf--; } TransAssert((Count == 2) && "Bad NestedNamespaceSpecifier!"); TransAssert((Offset < 0) && "Bad Offset Value!"); IdLocStart = IdLocStart.getLocWithOffset(Offset); TheRewriter.RemoveText(IdLocStart, ND->getNameAsString().length() - Offset); }
void RemoveUnusedStructField::removeOneInitExpr(const Expr *E) { TransAssert(NumFields && "NumFields cannot be zero!"); if (NumFields == 1) { RewriteHelper->replaceExpr(E, ""); return; } SourceRange ExpRange = E->getSourceRange(); SourceLocation StartLoc = ExpRange.getBegin(); SourceLocation EndLoc = ExpRange.getEnd(); 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)); }
void ASTDumper::dumpSourceRange(SourceRange R) { // Can't translate locations if a SourceManager isn't available. if (!SM) return; OS << " <"; dumpLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { OS << ", "; dumpLocation(R.getEnd()); } OS << ">"; // <t2.c:123:421[blah], t2.c:412:321> }
bool RVASTVisitor::rewriteFuncDecl(FunctionDecl *FD) { DeclarationNameInfo NameInfo = FD->getNameInfo(); SourceLocation NameInfoStartLoc = NameInfo.getBeginLoc(); SourceRange FuncDefRange = FD->getSourceRange(); SourceLocation FuncStartLoc = FuncDefRange.getBegin(); const char *FuncStartBuf = ConsumerInstance->SrcManager->getCharacterData(FuncStartLoc); const char *NameInfoStartBuf = ConsumerInstance->SrcManager->getCharacterData(NameInfoStartLoc); if (FuncStartBuf == NameInfoStartBuf) return true; int Offset = NameInfoStartBuf - FuncStartBuf; NameInfoStartBuf--; while ((*NameInfoStartBuf == '(') || (*NameInfoStartBuf == ' ') || (*NameInfoStartBuf == '\t') || (*NameInfoStartBuf == '\n')) { Offset--; NameInfoStartBuf--; } TransAssert(Offset >= 0); ConsumerInstance->Rewritten = true; return !(ConsumerInstance->TheRewriter.ReplaceText(FuncStartLoc, Offset, "void ")); }
// ISSUE: we will have bad transformation for the case below: // typedef struct S; // S *s; // ==> // typedef // int *s; // This is bad because we don't catch the implicit declaration of struct S. // But hopefully peephole pass will remove the keyword typedef, // then we will be fine. void EmptyStructToInt::removeRecordDecls(void) { for (RecordDecl::redecl_iterator I = TheRecordDecl->redecls_begin(), E = TheRecordDecl->redecls_end(); I != E; ++I) { const RecordDecl *RD = dyn_cast<RecordDecl>(*I); SourceRange Range = RD->getSourceRange(); SourceLocation LocEnd = Range.getEnd(); SourceLocation SemiLoc = Lexer::findLocationAfterToken(LocEnd, tok::semi, *SrcManager, Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true); // handle cases such as // struct S {} s; if (SemiLoc.isInvalid()) { if (!RD->isThisDeclarationADefinition()) return; SourceLocation RBLoc = RD->getRBraceLoc(); if (RBLoc.isInvalid()) return; RewriteHelper->removeTextFromLeftAt(SourceRange(RBLoc, RBLoc), '{', RBLoc); Rewritten = true; } else { LocEnd = RewriteHelper->getEndLocationUntil(Range, ';'); TheRewriter.RemoveText(SourceRange(Range.getBegin(), LocEnd)); Rewritten = true; } } }
void ExpandModularHeadersPPCallbacks::MacroExpands(const Token &MacroNameTok, const MacroDefinition &, SourceRange Range, const MacroArgs *) { // FIME: Figure out whether it's the right location to parse to. parseToLocation(Range.getBegin()); }
/// Tests whether a conversion according to N2844 is valid. TryStaticCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange) { // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". const RValueReferenceType *R = DestType->getAsRValueReferenceType(); if (!R) return TSC_NotApplicable; if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) return TSC_NotApplicable; // Because we try the reference downcast before this function, from now on // this is the only cast possibility, so we issue an error if we fail now. bool DerivedToBase; if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(), DerivedToBase) < Sema::Ref_Compatible_With_Added_Qualification) { Self.Diag(OpRange.getBegin(), diag::err_bad_lvalue_to_rvalue_cast) << SrcExpr->getType() << R->getPointeeType() << OpRange; return TSC_Failed; } // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation // than nothing. return TSC_Success; }
void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const { const Expr *receiver = msg.getInstanceReceiver(); if (!receiver) return; // FIXME: Enhance with value-tracking information instead of consulting // the type of the expression. const ObjCObjectPointerType* PT = receiver->getType()->getAs<ObjCObjectPointerType>(); if (!PT) return; const ObjCInterfaceDecl *OD = PT->getInterfaceDecl(); if (!OD) return; if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool")) return; if (releaseS.isNull()) releaseS = GetNullarySelector("release", C.getASTContext()); // Sending 'release' message? if (msg.getSelector() != releaseS) return; SourceRange R = msg.getSourceRange(); C.getBugReporter().EmitBasicReport("Use -drain instead of -release", "API Upgrade (Apple)", "Use -drain instead of -release when using NSAutoreleasePool " "and garbage collection", R.getBegin(), &R, 1); }
static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures, const IdentifierNamingCheck::NamingCheckId &Decl, SourceRange Range) { // Do nothing if the provided range is invalid. if (Range.getBegin().isInvalid() || Range.getEnd().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(Range.getBegin().getRawEncoding()).second) return; Failure.ShouldFix = Failure.ShouldFix && !Range.getBegin().isMacroID() && !Range.getEnd().isMacroID(); }
RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, bool Merged, bool ParseAllComments) : Range(SR), RawTextValid(false), BriefTextValid(false), IsAttached(false), IsAlmostTrailingComment(false), ParseAllComments(ParseAllComments), BeginLineValid(false), EndLineValid(false) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { Kind = RCK_Invalid; return; } if (!Merged) { // Guess comment kind. std::pair<CommentKind, bool> K = getCommentKind(RawText, ParseAllComments); Kind = K.first; IsTrailingComment = K.second; IsAlmostTrailingComment = RawText.startswith("//<") || RawText.startswith("/*<"); } else { Kind = RCK_Merged; IsTrailingComment = mergedCommentIsTrailingComment(RawText); } }
void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { VisitNamedDecl(D); SourceRange R = D->getAtEndRange(); Writer.AddSourceLocation(R.getBegin(), Record); Writer.AddSourceLocation(R.getEnd(), Record); // Abstract class (no need to define a stable pch::DECL code). }
bool PreprocessingRecord::rangeIntersectsConditionalDirective( SourceRange Range) const { if (Range.isInvalid()) return false; CondDirectiveLocsTy::const_iterator low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(), Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr)); if (low == CondDirectiveLocs.end()) return false; if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc())) return false; CondDirectiveLocsTy::const_iterator upp = std::upper_bound(low, CondDirectiveLocs.end(), Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr)); unsigned uppIdx; if (upp != CondDirectiveLocs.end()) uppIdx = upp->getIdx(); else uppIdx = 0; return low->getIdx() != uppIdx; }
bool ReduceClassTemplateParameter::reducePartialSpec( const ClassTemplatePartialSpecializationDecl *PartialD) { const CXXRecordDecl *CXXRD = TheClassTemplateDecl->getTemplatedDecl(); // it CXXRD has definition, skip it to avoid duplication if (CXXRD->hasDefinition()) return false; if (!isValidForReduction(PartialD)) return false; const ASTTemplateArgumentListInfo *ArgList = PartialD->getTemplateArgsAsWritten(); const TemplateArgumentLoc *ArgLocs = ArgList->getTemplateArgs(); unsigned NumArgsAsWritten = ArgList->NumTemplateArgs; const TemplateArgumentLoc FirstArgLoc = ArgLocs[0]; SourceRange FirstRange = FirstArgLoc.getSourceRange(); SourceLocation StartLoc = FirstRange.getBegin(); const TemplateArgumentLoc LastArgLoc = ArgLocs[NumArgsAsWritten - 1]; SourceRange LastRange = LastArgLoc.getSourceRange(); SourceLocation EndLoc = RewriteHelper->getEndLocationUntil(LastRange, '>'); RewriteHelper->removeTextFromLeftAt(SourceRange(StartLoc, EndLoc), '<', EndLoc); return true; }
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)); }
void TransformActionsImpl::commitReplace(SourceRange range, SourceRange replacementRange) { RangeComparison comp = CharRange::compare(replacementRange, range, Ctx.getSourceManager(), PP); assert(comp == Range_Contained); if (comp != Range_Contained) return; // Although we asserted, be extra safe for release build. if (range.getBegin() != replacementRange.getBegin()) addRemoval(CharSourceRange::getCharRange(range.getBegin(), replacementRange.getBegin())); if (replacementRange.getEnd() != range.getEnd()) addRemoval(CharSourceRange::getTokenRange( getLocForEndOfToken(replacementRange.getEnd(), Ctx.getSourceManager(), PP), range.getEnd())); }
void DefaultArgumentsCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *S = Result.Nodes.getNodeAs<CXXDefaultArgExpr>("stmt")) { diag(S->getUsedLocation(), "calling a function that uses a default argument is disallowed"); diag(S->getParam()->getBeginLoc(), "default parameter was declared here", DiagnosticIDs::Note); } else if (const ParmVarDecl *D = Result.Nodes.getNodeAs<ParmVarDecl>("decl")) { SourceRange DefaultArgRange = D->getDefaultArgRange(); if (DefaultArgRange.getEnd() != D->getEndLoc()) { return; } else if (DefaultArgRange.getBegin().isMacroID()) { diag(D->getBeginLoc(), "declaring a parameter with a default argument is disallowed"); } else { SourceLocation StartLocation = D->getName().empty() ? D->getBeginLoc() : D->getLocation(); SourceRange RemovalRange(Lexer::getLocForEndOfToken( StartLocation, 0, *Result.SourceManager, Result.Context->getLangOpts() ), DefaultArgRange.getEnd() ); diag(D->getBeginLoc(), "declaring a parameter with a default argument is disallowed") << D << FixItHint::CreateRemoval(RemovalRange); } } }
bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { if (range.isInvalid()) return false; bool cleared = false; ListTy::iterator I = List.begin(); while (I != List.end()) { FullSourceLoc diagLoc = I->getLocation(); if ((IDs.empty() || // empty means clear all diagnostics in the range. std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && (diagLoc == range.getEnd() || diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { cleared = true; ListTy::iterator eraseS = I++; while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) ++I; // Clear the diagnostic and any notes following it. List.erase(eraseS, I); continue; } ++I; } return cleared; }
bool RewriteUtils::getEntireDeclGroupStrAndRemove(DeclGroupRef DGR, std::string &Str) { Decl *FirstD, *LastD; if (DGR.isSingleDecl()) { FirstD = DGR.getSingleDecl(); LastD = FirstD; } else { DeclGroupRef::iterator I = DGR.begin(); FirstD = (*I); DeclGroupRef::iterator E = DGR.end(); --E; LastD = (*E); } SourceRange FirstRange = FirstD->getSourceRange(); SourceLocation StartLoc = FirstRange.getBegin(); SourceRange LastRange = LastD->getSourceRange(); SourceLocation EndLoc = getEndLocationUntil(LastRange, ';'); getStringBetweenLocs(Str, StartLoc, EndLoc); return !TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc)); }
bool ClangDocHTML::HandleComment(Preprocessor &PP, SourceRange Comment) { if(Comment.isValid()) { if(astConsumer->sourceManager->isInSystemHeader(Comment.getBegin())) { return false; } /* bool bInvalid = false; const char *cbegin = astConsumer->sourceManager->getCharacterData(Comment.getBegin(), &bInvalid); const char *cend = astConsumer->sourceManager->getCharacterData(Comment.getEnd(), &bInvalid); llvm::StringRef string = llvm::StringRef(cbegin, cend-cbegin);*/ //Decl *decl = 0; /*if(string.startswith("///<")) { decl = lastDecl; decl->print(*Out); }*/ commentsList.push_back(Comment); //lastComment = commentsByDecl.insert(CommentsByDeclPair(decl, string) ); //*Out << string << "<br/>\n"; } return false; }
void ReplaceFunctionDefWithDecl::removeCtorInitializers( const CXXConstructorDecl *Ctor) { if (!getNumWrittenInitializers(Ctor)) return; CXXConstructorDecl::init_const_iterator I = Ctor->init_begin(); while (!(*I)->isWritten()) ++I; const CXXCtorInitializer *FirstInit = (*I); SourceRange Range = FirstInit->getSourceRange(); SourceLocation LocStart = Range.getBegin(); // RewriteHelper->removeTextFromLeftAt(Range, ':', // LocStart.getLocWithOffset(-1)); // make sure we handle cases like: // namespace NS { struct A {}; } // struct B : NS::A { B() : NS::A() {} }; SourceLocation Loc = RewriteHelper->getLocationFromLeftUntil(LocStart, ':'); Loc = RewriteHelper->getLocationFromLeftUntil(LocStart, ')'); TheRewriter.RemoveText(SourceRange(Loc.getLocWithOffset(1), LocStart.getLocWithOffset(-1))); CXXConstructorDecl::init_const_iterator E = Ctor->init_end(); --E; while (!(*E)->isWritten()) --E; const CXXCtorInitializer *LastInit = (*E); TransAssert(LastInit->isWritten() && "Init is not written!"); SourceLocation LocEnd = LastInit->getSourceRange().getEnd(); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); }
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(), "}"); }
// ISSUE: The transformation is known to go wrong in the following case: // template<typename T1, typename T2> struct S; // template<typename T1, typename T2> struct S<T2, T1>; void ReduceClassTemplateParameter::removeParameterFromPartialSpecs() { SmallVector<ClassTemplatePartialSpecializationDecl *, 10> PartialDecls; TheClassTemplateDecl->getPartialSpecializations(PartialDecls); for (SmallVector<ClassTemplatePartialSpecializationDecl *, 10>::iterator I = PartialDecls.begin(), E = PartialDecls.end(); I != E; ++I) { const ClassTemplatePartialSpecializationDecl *PartialD = (*I); const ASTTemplateArgumentListInfo *ArgList = PartialD->getTemplateArgsAsWritten(); const TemplateArgumentLoc *ArgLocs = ArgList->getTemplateArgs(); unsigned NumArgs = ArgList->NumTemplateArgs; if (!ArgLocs) continue; // handle a special case where we could reduce a partial specialization // to a class template definition, e.g.: // template<typename T1, typename T2> struct A; // template<typename T1> struct A<T1, int> { }; // ==> // template<typename T1> struct A; // template<typename T1> struct A { }; if (reducePartialSpec(PartialD)) continue; if ((TheParameterIndex >= NumArgs) && hasDefaultArg) return; TransAssert((TheParameterIndex < NumArgs) && "Bad NumArgs from partial template decl!"); TemplateArgumentLoc ArgLoc = ArgLocs[TheParameterIndex]; TemplateArgument Arg = ArgLoc.getArgument(); removeOneParameterFromPartialDecl(PartialD, Arg); SourceRange Range = ArgLoc.getSourceRange(); if (NumArgs == 1) { SourceLocation StartLoc = Range.getBegin(); SourceLocation EndLoc = RewriteHelper->getEndLocationUntil(Range, '>'); EndLoc = EndLoc.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); } else if ((TheParameterIndex + 1) == NumArgs) { // Seems there is no getRAngleLoc() utility for // template arguments from a partial specialization SourceLocation EndLoc = RewriteHelper->getEndLocationUntil(Range, '>'); EndLoc = EndLoc.getLocWithOffset(-1); RewriteHelper->removeTextFromLeftAt(Range, ',', EndLoc); } else { RewriteHelper->removeTextUntil(Range, ','); } } }
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; }