-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[BoundsSafety] build TypeLoc for CountAttributedType #167287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This adds attribute SourceRange to CountAttributedTypeLoc and populates it. The following commit will change diagnostics to use this information. Fixes llvm#113582
This replaces the count expr source location used for note_counted_by_consider_using_sized_by with the actual attribute location fetched from TypeLof, except in the rare case where we couldn't find a TypeLoc. It also attaches a fix-it hint, now that we have the proper source range. Fixes llvm#113585
|
@llvm/pr-subscribers-clang Author: Henrik G. Olsson (hnrklssn) ChangesThis adds attribute SourceRange to CountAttributedTypeLoc and populates it, then uses it to replace a not-quite-correct source location fetched from the count expression. Full diff: https://github.com/llvm/llvm-project/pull/167287.diff 4 Files Affected:
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 2cefaa9611c98..0cf17c463d6cd 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -19,6 +19,7 @@
#include "clang/AST/NestedNameSpecifierBase.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TypeBase.h"
+#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
@@ -1303,7 +1304,10 @@ class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<ObjCObjectTypeLoc,
}
};
-struct BoundsAttributedLocInfo {};
+class Sema;
+struct BoundsAttributedLocInfo {
+ SourceRange Range;
+};
class BoundsAttributedTypeLoc
: public ConcreteTypeLoc<UnqualTypeLoc, BoundsAttributedTypeLoc,
BoundsAttributedType, BoundsAttributedLocInfo> {
@@ -1311,10 +1315,17 @@ class BoundsAttributedTypeLoc
TypeLoc getInnerLoc() const { return getInnerTypeLoc(); }
QualType getInnerType() const { return getTypePtr()->desugar(); }
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
- // nothing to do
+ setAttrRange({Loc, Loc});
}
- // LocalData is empty and TypeLocBuilder doesn't handle DataSize 1.
- unsigned getLocalDataSize() const { return 0; }
+ void setAttrRange(SourceRange Range) {
+ getLocalData()->Range = Range;
+ }
+ SourceRange getAttrRange() const { return getLocalData()->Range; }
+
+ StringRef getAttrNameAsWritten(Sema &S) const;
+ SourceRange getAttrNameRange(Sema &S) const;
+
+ unsigned getLocalDataSize() const { return sizeof(BoundsAttributedLocInfo); }
};
class CountAttributedTypeLoc final
@@ -1325,8 +1336,6 @@ class CountAttributedTypeLoc final
Expr *getCountExpr() const { return getTypePtr()->getCountExpr(); }
bool isCountInBytes() const { return getTypePtr()->isCountInBytes(); }
bool isOrNull() const { return getTypePtr()->isOrNull(); }
-
- SourceRange getLocalSourceRange() const;
};
struct MacroQualifiedLocInfo {
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index f54ccf0932bc7..66f9e3c67df84 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -590,10 +590,6 @@ SourceRange AttributedTypeLoc::getLocalSourceRange() const {
return getAttr() ? getAttr()->getRange() : SourceRange();
}
-SourceRange CountAttributedTypeLoc::getLocalSourceRange() const {
- return getCountExpr() ? getCountExpr()->getSourceRange() : SourceRange();
-}
-
SourceRange BTFTagAttributedTypeLoc::getLocalSourceRange() const {
return getAttr() ? getAttr()->getRange() : SourceRange();
}
diff --git a/clang/lib/Sema/SemaBoundsSafety.cpp b/clang/lib/Sema/SemaBoundsSafety.cpp
index de9adf8ef5a1b..a699c9d116b15 100644
--- a/clang/lib/Sema/SemaBoundsSafety.cpp
+++ b/clang/lib/Sema/SemaBoundsSafety.cpp
@@ -11,6 +11,14 @@
/// (e.g. `counted_by`)
///
//===----------------------------------------------------------------------===//
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeBase.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Sema.h"
@@ -231,9 +239,69 @@ bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes,
return false;
}
+// FIXME: for some reason diagnostics highlight the end character, while
+// getSourceText() does not include the end character.
+static SourceRange getAttrNameRangeImpl(Sema &S, SourceLocation Begin,
+ bool IsForDiagnostics) {
+ SourceManager &SM = S.getSourceManager();
+ SourceLocation TokenStart = Begin;
+ while (TokenStart.isMacroID())
+ TokenStart = SM.getImmediateExpansionRange(TokenStart).getBegin();
+ unsigned Offset = IsForDiagnostics ? 1 : 0;
+ SourceLocation End = S.getLocForEndOfToken(TokenStart, Offset);
+ return {TokenStart, End};
+}
+
+StringRef BoundsAttributedTypeLoc::getAttrNameAsWritten(Sema &S) const {
+ SourceRange Range = getAttrNameRangeImpl(S, getAttrRange().getBegin(), false);
+ CharSourceRange NameRange = CharSourceRange::getCharRange(Range);
+ return Lexer::getSourceText(NameRange, S.getSourceManager(), S.getLangOpts());
+}
+
+SourceRange BoundsAttributedTypeLoc::getAttrNameRange(Sema &S) const {
+ return getAttrNameRangeImpl(S, getAttrRange().getBegin(), true);
+}
+
+static TypeSourceInfo *getTSI(const Decl *D) {
+ if (const auto* DD = dyn_cast<DeclaratorDecl>(D)) {
+ return DD->getTypeSourceInfo();
+ }
+ return nullptr;
+}
+
+struct TypeLocFinder : public ConstStmtVisitor<TypeLocFinder, TypeLoc> {
+ TypeLoc VisitParenExpr(const ParenExpr* E) {
+ return Visit(E->getSubExpr());
+ }
+
+ TypeLoc VisitDeclRefExpr(const DeclRefExpr *E) {
+ return getTSI(E->getDecl())->getTypeLoc();
+ }
+
+ TypeLoc VisitMemberExpr(const MemberExpr *E) {
+ return getTSI(E->getMemberDecl())->getTypeLoc();
+ }
+
+ TypeLoc VisitExplicitCastExpr(const ExplicitCastExpr *E) {
+ return E->getTypeInfoAsWritten()->getTypeLoc();
+ }
+
+ TypeLoc VisitCallExpr(const CallExpr *E) {
+ if (const auto *D = E->getCalleeDecl()) {
+ FunctionTypeLoc FTL = getTSI(D)->getTypeLoc().getAs<FunctionTypeLoc>();
+ if (FTL.isNull()) {
+ return FTL;
+ }
+ return FTL.getReturnLoc();
+ }
+ return {};
+ }
+};
+
static void EmitIncompleteCountedByPointeeNotes(Sema &S,
const CountAttributedType *CATy,
- NamedDecl *IncompleteTyDecl) {
+ NamedDecl *IncompleteTyDecl,
+ TypeLoc TL) {
assert(IncompleteTyDecl == nullptr || isa<TypeDecl>(IncompleteTyDecl));
if (IncompleteTyDecl) {
@@ -253,20 +321,36 @@ static void EmitIncompleteCountedByPointeeNotes(Sema &S,
<< CATy->getPointeeType();
}
- // Suggest using __sized_by(_or_null) instead of __counted_by(_or_null) as
- // __sized_by(_or_null) doesn't have the complete type restriction.
- //
- // We use the source range of the expression on the CountAttributedType as an
- // approximation for the source range of the attribute. This isn't quite right
- // but isn't easy to fix right now.
- //
- // TODO: Implement logic to find the relevant TypeLoc for the attribute and
- // get the SourceRange from that (#113582).
- //
- // TODO: We should emit a fix-it here.
- SourceRange AttrSrcRange = CATy->getCountExpr()->getSourceRange();
+ CountAttributedTypeLoc CATL;
+ if (!TL.isNull())
+ CATL = TL.getAs<CountAttributedTypeLoc>();
+
+ if (CATL.isNull()) {
+ // Fall back to pointing to the count expr - not great, but close enough.
+ // This should happen rarely, if ever.
+ S.Diag(CATy->getCountExpr()->getExprLoc(),
+ diag::note_counted_by_consider_using_sized_by)
+ << CATy->isOrNull();
+ return;
+ }
+ SourceRange AttrSrcRange = CATL.getAttrNameRange(S);
+
+ StringRef Spelling = CATL.getAttrNameAsWritten(S);
+ StringRef FixedSpelling;
+ if (Spelling == "__counted_by")
+ FixedSpelling = "__sized_by";
+ else if (Spelling == "counted_by")
+ FixedSpelling = "sized_by";
+ else if (Spelling == "__counted_by_or_null")
+ FixedSpelling = "__sized_by_or_null";
+ else if (Spelling == "counted_by_or_null")
+ FixedSpelling = "sized_by_or_null";
+ FixItHint Fix;
+ if (!FixedSpelling.empty())
+ Fix = FixItHint::CreateReplacement(AttrSrcRange, FixedSpelling);
+
S.Diag(AttrSrcRange.getBegin(), diag::note_counted_by_consider_using_sized_by)
- << CATy->isOrNull() << AttrSrcRange;
+ << CATy->isOrNull() << AttrSrcRange << Fix;
}
static std::tuple<const CountAttributedType *, QualType>
@@ -335,7 +419,11 @@ static bool CheckAssignmentToCountAttrPtrWithIncompletePointeeTy(
<< CATy->getAttributeName(/*WithMacroPrefix=*/true) << PointeeTy
<< CATy->isOrNull() << RHSExpr->getSourceRange();
- EmitIncompleteCountedByPointeeNotes(S, CATy, IncompleteTyDecl);
+ TypeLoc TL;
+ if (TypeSourceInfo *TSI = getTSI(Assignee))
+ TL = TSI->getTypeLoc();
+
+ EmitIncompleteCountedByPointeeNotes(S, CATy, IncompleteTyDecl, TL);
return false; // check failed
}
@@ -408,7 +496,8 @@ bool Sema::BoundsSafetyCheckUseOfCountAttrPtr(const Expr *E) {
<< CATy->getAttributeName(/*WithMacroPrefix=*/true) << CATy->isOrNull()
<< E->getSourceRange();
- EmitIncompleteCountedByPointeeNotes(*this, CATy, IncompleteTyDecl);
+ TypeLoc TL = TypeLocFinder().Visit(E);
+ EmitIncompleteCountedByPointeeNotes(*this, CATy, IncompleteTyDecl, TL);
return false;
}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index a9e7b44ac9d73..1753261822755 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -10,10 +10,12 @@
//
//===----------------------------------------------------------------------===//
+#include "TypeLocBuilder.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -24,6 +26,8 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Cuda.h"
#include "clang/Basic/DarwinSDKInfo.h"
@@ -6580,9 +6584,14 @@ static void handleCountedByAttrField(Sema &S, Decl *D, const ParsedAttr &AL) {
if (S.CheckCountedByAttrOnField(FD, CountExpr, CountInBytes, OrNull))
return;
+ TypeLocBuilder TLB;
QualType CAT = S.BuildCountAttributedArrayOrPointerType(
FD->getType(), CountExpr, CountInBytes, OrNull);
+ TLB.pushFullCopy(FD->getTypeSourceInfo()->getTypeLoc());
+ CountAttributedTypeLoc CATL = TLB.push<CountAttributedTypeLoc>(CAT);
+ CATL.setAttrRange(AL.getRange());
FD->setType(CAT);
+ FD->setTypeSourceInfo(TLB.getTypeSourceInfo(S.getASTContext(), CAT));
}
static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
Just found out about |
Also adds a test case checking the source ranges and fix-its.
|
Should be ready for review now :) |
zmodem
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just nits from my side. Otherwise lgtm.
|
|
||
| // FIXME: for some reason diagnostics highlight the end character, while | ||
| // getSourceText() does not include the end character. | ||
| static SourceRange getAttrNameRangeImpl(Sema &S, SourceLocation Begin, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @hnrklssn! This looks great. Not that I'm suggesting to do right now, but I wonder if we want to embed Attr * in bounds-attributed types eventually to preserve all attribute related stuffs, and whether that would also remove the needs for custom handing of ranges like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Attr would have the same range (and MacroII seems to have basically the same range as well), since it would also get its range from ParsedAttr. I'm not sure whether there's really that much else we would want in Attr, and since we don't currently allocate an Attr for counted_by it felt more sensible to just grab the source range directly. If we figure out a use case for Attr we can always change it later.
This adds attribute SourceRange to CountAttributedTypeLoc and populates it, then uses it to replace a not-quite-correct source location fetched from the count expression.
Fixes #113582
Fixes #113585