1111// / (e.g. `counted_by`)
1212// /
1313// ===----------------------------------------------------------------------===//
14+ #include " clang/AST/Decl.h"
15+ #include " clang/AST/Expr.h"
16+ #include " clang/AST/StmtVisitor.h"
17+ #include " clang/AST/TypeBase.h"
18+ #include " clang/AST/TypeLoc.h"
19+ #include " clang/Basic/Diagnostic.h"
20+ #include " clang/Basic/SourceLocation.h"
21+ #include " clang/Basic/SourceManager.h"
1422#include " clang/Lex/Lexer.h"
1523#include " clang/Sema/Initialization.h"
1624#include " clang/Sema/Sema.h"
@@ -231,9 +239,69 @@ bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes,
231239 return false ;
232240}
233241
242+ // FIXME: for some reason diagnostics highlight the end character, while
243+ // getSourceText() does not include the end character.
244+ static SourceRange getAttrNameRangeImpl (Sema &S, SourceLocation Begin,
245+ bool IsForDiagnostics) {
246+ SourceManager &SM = S.getSourceManager ();
247+ SourceLocation TokenStart = Begin;
248+ while (TokenStart.isMacroID ())
249+ TokenStart = SM.getImmediateExpansionRange (TokenStart).getBegin ();
250+ unsigned Offset = IsForDiagnostics ? 1 : 0 ;
251+ SourceLocation End = S.getLocForEndOfToken (TokenStart, Offset);
252+ return {TokenStart, End};
253+ }
254+
255+ StringRef BoundsAttributedTypeLoc::getAttrNameAsWritten (Sema &S) const {
256+ SourceRange Range = getAttrNameRangeImpl (S, getAttrRange ().getBegin (), false );
257+ CharSourceRange NameRange = CharSourceRange::getCharRange (Range);
258+ return Lexer::getSourceText (NameRange, S.getSourceManager (), S.getLangOpts ());
259+ }
260+
261+ SourceRange BoundsAttributedTypeLoc::getAttrNameRange (Sema &S) const {
262+ return getAttrNameRangeImpl (S, getAttrRange ().getBegin (), true );
263+ }
264+
265+ static TypeSourceInfo *getTSI (const Decl *D) {
266+ if (const auto * DD = dyn_cast<DeclaratorDecl>(D)) {
267+ return DD->getTypeSourceInfo ();
268+ }
269+ return nullptr ;
270+ }
271+
272+ struct TypeLocFinder : public ConstStmtVisitor <TypeLocFinder, TypeLoc> {
273+ TypeLoc VisitParenExpr (const ParenExpr* E) {
274+ return Visit (E->getSubExpr ());
275+ }
276+
277+ TypeLoc VisitDeclRefExpr (const DeclRefExpr *E) {
278+ return getTSI (E->getDecl ())->getTypeLoc ();
279+ }
280+
281+ TypeLoc VisitMemberExpr (const MemberExpr *E) {
282+ return getTSI (E->getMemberDecl ())->getTypeLoc ();
283+ }
284+
285+ TypeLoc VisitExplicitCastExpr (const ExplicitCastExpr *E) {
286+ return E->getTypeInfoAsWritten ()->getTypeLoc ();
287+ }
288+
289+ TypeLoc VisitCallExpr (const CallExpr *E) {
290+ if (const auto *D = E->getCalleeDecl ()) {
291+ FunctionTypeLoc FTL = getTSI (D)->getTypeLoc ().getAs <FunctionTypeLoc>();
292+ if (FTL.isNull ()) {
293+ return FTL;
294+ }
295+ return FTL.getReturnLoc ();
296+ }
297+ return {};
298+ }
299+ };
300+
234301static void EmitIncompleteCountedByPointeeNotes (Sema &S,
235302 const CountAttributedType *CATy,
236- NamedDecl *IncompleteTyDecl) {
303+ NamedDecl *IncompleteTyDecl,
304+ TypeLoc TL) {
237305 assert (IncompleteTyDecl == nullptr || isa<TypeDecl>(IncompleteTyDecl));
238306
239307 if (IncompleteTyDecl) {
@@ -253,20 +321,36 @@ static void EmitIncompleteCountedByPointeeNotes(Sema &S,
253321 << CATy->getPointeeType ();
254322 }
255323
256- // Suggest using __sized_by(_or_null) instead of __counted_by(_or_null) as
257- // __sized_by(_or_null) doesn't have the complete type restriction.
258- //
259- // We use the source range of the expression on the CountAttributedType as an
260- // approximation for the source range of the attribute. This isn't quite right
261- // but isn't easy to fix right now.
262- //
263- // TODO: Implement logic to find the relevant TypeLoc for the attribute and
264- // get the SourceRange from that (#113582).
265- //
266- // TODO: We should emit a fix-it here.
267- SourceRange AttrSrcRange = CATy->getCountExpr ()->getSourceRange ();
324+ CountAttributedTypeLoc CATL;
325+ if (!TL.isNull ())
326+ CATL = TL.getAs <CountAttributedTypeLoc>();
327+
328+ if (CATL.isNull ()) {
329+ // Fall back to pointing to the count expr - not great, but close enough.
330+ // This should happen rarely, if ever.
331+ S.Diag (CATy->getCountExpr ()->getExprLoc (),
332+ diag::note_counted_by_consider_using_sized_by)
333+ << CATy->isOrNull ();
334+ return ;
335+ }
336+ SourceRange AttrSrcRange = CATL.getAttrNameRange (S);
337+
338+ StringRef Spelling = CATL.getAttrNameAsWritten (S);
339+ StringRef FixedSpelling;
340+ if (Spelling == " __counted_by" )
341+ FixedSpelling = " __sized_by" ;
342+ else if (Spelling == " counted_by" )
343+ FixedSpelling = " sized_by" ;
344+ else if (Spelling == " __counted_by_or_null" )
345+ FixedSpelling = " __sized_by_or_null" ;
346+ else if (Spelling == " counted_by_or_null" )
347+ FixedSpelling = " sized_by_or_null" ;
348+ FixItHint Fix;
349+ if (!FixedSpelling.empty ())
350+ Fix = FixItHint::CreateReplacement (AttrSrcRange, FixedSpelling);
351+
268352 S.Diag (AttrSrcRange.getBegin (), diag::note_counted_by_consider_using_sized_by)
269- << CATy->isOrNull () << AttrSrcRange;
353+ << CATy->isOrNull () << AttrSrcRange << Fix ;
270354}
271355
272356static std::tuple<const CountAttributedType *, QualType>
@@ -335,7 +419,11 @@ static bool CheckAssignmentToCountAttrPtrWithIncompletePointeeTy(
335419 << CATy->getAttributeName (/* WithMacroPrefix=*/ true ) << PointeeTy
336420 << CATy->isOrNull () << RHSExpr->getSourceRange ();
337421
338- EmitIncompleteCountedByPointeeNotes (S, CATy, IncompleteTyDecl);
422+ TypeLoc TL;
423+ if (TypeSourceInfo *TSI = getTSI (Assignee))
424+ TL = TSI->getTypeLoc ();
425+
426+ EmitIncompleteCountedByPointeeNotes (S, CATy, IncompleteTyDecl, TL);
339427 return false ; // check failed
340428}
341429
@@ -408,7 +496,8 @@ bool Sema::BoundsSafetyCheckUseOfCountAttrPtr(const Expr *E) {
408496 << CATy->getAttributeName (/* WithMacroPrefix=*/ true ) << CATy->isOrNull ()
409497 << E->getSourceRange ();
410498
411- EmitIncompleteCountedByPointeeNotes (*this , CATy, IncompleteTyDecl);
499+ TypeLoc TL = TypeLocFinder ().Visit (E);
500+ EmitIncompleteCountedByPointeeNotes (*this , CATy, IncompleteTyDecl, TL);
412501 return false ;
413502}
414503
0 commit comments