How to compare Attr location with Decl location?

I am using an AST matcher and would like to prevent an annotation attribute from being placed on an out-of-line constructor definition.

class Foo {
explicit Foo(int); // ok
[[clang::annotate(“implicit”)]] Foo(int); // ok
};

explicit Foo::Foo() {} // disallowed
[[clang::annotate(“implicit”)]] Foo::Foo(int) {} // should be disallowed

However it seems that when I match the out-of-line decl, decl->specific_attrs<AnnotateAttr>() contains the attribute even if it was placed on the original in-class declaration and not on the out-of-line definition.

How can I determine whether an Attr* was written on the out-of-line decl?

I tried checking (!(attr->getLocation() < decl->getLocStart()) && !(decl->getLocEnd() < attr->getLocation())), however it seems the two locations are not comparable. When I look at their getRawEncoding()s, the attribute has values in ranges like 2147587494-2147587527 while the decl’s values are more reasonable, such as 3049-3079. I couldn’t find any documentation about attribute source locations being negative.

Thanks,

I am using an AST matcher and would like to prevent an annotation
attribute from being placed on an out-of-line constructor definition.

    class Foo {
        explicit Foo(int); // ok
        [[clang::annotate("implicit")]] Foo(int); // ok
    };

    explicit Foo::Foo() {} // *disallowed*
    [[clang::annotate("implicit")]] Foo::Foo(int) {} // *should be
disallowed*

However it seems that when I match the out-of-line decl,
`decl->specific_attrs<AnnotateAttr>()` contains the attribute *even if it
was placed on the original in-class declaration* and not on the
out-of-line definition.

How can I determine whether an Attr* was written on the out-of-line decl?

You can look over the AnnotateAttr(s) on the out-of-line declaration and
check !Attr::isInherited() to see whether they were written on that
declaration.

I tried checking (!(attr->getLocation() < decl->getLocStart()) &&
!(decl->getLocEnd() < attr->getLocation())), however it seems the two
locations are not comparable. When I look at their getRawEncoding()s, the
attribute has values in ranges like 2147587494-2147587527 while the decl's
values are more reasonable, such as 3049-3079.

The numerical values of source locations (and their comparison order under
<) have no strong relation to the semantics of the program and should be
thought of as arbitrary; we give a total order under operator< to
facilitate use of SourceLocations in std::map and the like. (You can use
SourceManager::isBeforeInTranslationUnit if you want to compare source
locations in order of appearance, in cases where that makes sense.)
Currently, the high bit of source locations indicates that they represent a
location within a macro expansion (presumably in your actual testcase the
attribute was coming from a macro expansion), but it would be unwise to
rely on that and you should use the high-level semantically-aware
functionality in SourceManager instead.

I couldn't find any documentation about attribute source locations being
negative.

The documentation comment for the SourceLocation class describes the
encoding we currently use:

/// Technically, a source location is simply an offset into the manager's
view
/// of the input source, which is all input buffers (including macro
/// expansions) concatenated in an effectively arbitrary order. The manager
/// actually maintains two blocks of input buffers. One, starting at offset
/// 0 and growing upwards, contains all buffers from this module. The other,
/// starting at the highest possible offset and growing downwards, contains
/// buffers of loaded modules.
///
/// In addition, one bit of SourceLocation is used for quick access to the
/// information whether the location is in a file or a macro expansion.