Skip to content

Commit 3c9fad5

Browse files
committed
[clang] extend external_source_symbol attribute with the USR clause
Allow the user to specify a concrete USR in the external_source_symbol attribute. That will let Clang's indexer to use Swift USRs for Swift declarations that are represented with C++ declarations. Precommit : https://reviews.llvm.org/D141324
1 parent 36c016a commit 3c9fad5

16 files changed

+200
-52
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,23 +294,22 @@ class VariadicEnumArgument<string name, string type, list<string> values,
294294
class AttrArgument<string name, bit opt = 0> : Argument<name, opt>;
295295

296296
// This handles one spelling of an attribute.
297-
class Spelling<string name, string variety> {
297+
class Spelling<string name, string variety, int version = 1> {
298298
string Name = name;
299299
string Variety = variety;
300+
int Version = version;
300301
}
301302

302303
class GNU<string name> : Spelling<name, "GNU">;
303304
class Declspec<string name> : Spelling<name, "Declspec">;
304305
class Microsoft<string name> : Spelling<name, "Microsoft">;
305306
class CXX11<string namespace, string name, int version = 1>
306-
: Spelling<name, "CXX11"> {
307+
: Spelling<name, "CXX11", version> {
307308
string Namespace = namespace;
308-
int Version = version;
309309
}
310310
class C2x<string namespace, string name, int version = 1>
311-
: Spelling<name, "C2x"> {
311+
: Spelling<name, "C2x", version> {
312312
string Namespace = namespace;
313-
int Version = version;
314313
}
315314

316315
class Keyword<string name> : Spelling<name, "Keyword">;
@@ -328,7 +327,8 @@ class GCC<string name, bit allowInC = 1> : Spelling<name, "GCC"> {
328327
// The Clang spelling implies GNU<name>, CXX11<"clang", name>, and optionally,
329328
// C2x<"clang", name>. This spelling should be used for any Clang-specific
330329
// attributes.
331-
class Clang<string name, bit allowInC = 1> : Spelling<name, "Clang"> {
330+
class Clang<string name, bit allowInC = 1, int version = 1>
331+
: Spelling<name, "Clang", version> {
332332
bit AllowInC = allowInC;
333333
}
334334

@@ -965,10 +965,12 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
965965
}
966966

967967
def ExternalSourceSymbol : InheritableAttr {
968-
let Spellings = [Clang<"external_source_symbol">];
968+
let Spellings = [Clang<"external_source_symbol", /*allowInC=*/1,
969+
/*version=*/20230206>];
969970
let Args = [StringArgument<"language", 1>,
970971
StringArgument<"definedIn", 1>,
971-
BoolArgument<"generatedDeclaration", 1>];
972+
BoolArgument<"generatedDeclaration", 1>,
973+
StringArgument<"USR", 1>];
972974
let HasCustomParsing = 1;
973975
let Subjects = SubjectList<[Named]>;
974976
let Documentation = [ExternalSourceSymbolDocs];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,6 +1909,19 @@ defined_in=\ *string-literal*
19091909
source containers are modules, so ``defined_in`` should specify the Swift
19101910
module name.
19111911

1912+
USR=\ *string-literal*
1913+
String that specifies a unified symbol resolution (USR) value for this
1914+
declaration. USR string uniquely identifies this particular declaration, and
1915+
is typically used when constructing an index of a codebase.
1916+
The USR value in this attribute is expected to be generated by an external
1917+
compiler that compiled the native declaration using its original source
1918+
language. The exact format of the USR string and its other attributes
1919+
are determined by the specification of this declaration's source language.
1920+
When not specified, Clang's indexer will use the Clang USR for this symbol.
1921+
User can query to see if Clang supports the use of the ``USR`` clause in
1922+
the ``external_source_symbol`` attribute with
1923+
``__has_attribute(external_source_symbol) >= 20230206``.
1924+
19121925
generated_declaration
19131926
This declaration was automatically generated by some tool.
19141927

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def err_expected_colon_after_setter_name : Error<
5555
def err_expected_string_literal : Error<"expected string literal "
5656
"%select{in %1|for diagnostic message in static_assert|"
5757
"for optional message in 'availability' attribute|"
58-
"for %select{language|source container}1 name in "
58+
"for %select{language name|source container name|USR}1 in "
5959
"'external_source_symbol' attribute}0">;
6060
def err_invalid_string_udl : Error<
6161
"string literal with user-defined suffix cannot be used here">;

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ def err_availability_query_repeated_star : Error<
10991099

11001100
// External source symbol attribute
11011101
def err_external_source_symbol_expected_keyword : Error<
1102-
"expected 'language', 'defined_in', or 'generated_declaration'">;
1102+
"expected 'language', 'defined_in', 'generated_declaration', or 'USR'">;
11031103
def err_external_source_symbol_duplicate_clause : Error<
11041104
"duplicate %0 clause in an 'external_source_symbol' attribute">;
11051105

clang/include/clang/Parse/Parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class Parser : public CodeCompletionHandler {
155155

156156
/// Identifiers used by the 'external_source_symbol' attribute.
157157
IdentifierInfo *Ident_language, *Ident_defined_in,
158-
*Ident_generated_declaration;
158+
*Ident_generated_declaration, *Ident_USR;
159159

160160
/// C++11 contextual keywords.
161161
mutable IdentifierInfo *Ident_final;

clang/lib/Index/USRGeneration.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,15 @@ bool clang::index::generateUSRForDecl(const Decl *D,
11391139
// C++'s operator new function, can have invalid locations but it is fine to
11401140
// create USRs that can identify them.
11411141

1142+
// Check if the declaration has explicit external USR specified.
1143+
auto *CD = D->getCanonicalDecl();
1144+
if (auto *ExternalSymAttr = CD->getAttr<ExternalSourceSymbolAttr>()) {
1145+
if (!ExternalSymAttr->getUSR().empty()) {
1146+
llvm::raw_svector_ostream Out(Buf);
1147+
Out << ExternalSymAttr->getUSR();
1148+
return false;
1149+
}
1150+
}
11421151
USRGenerator UG(&D->getASTContext(), Buf);
11431152
UG.Visit(D);
11441153
return UG.ignoreResults();

clang/lib/Parse/ParseDecl.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
13191319
/// keyword-arg:
13201320
/// 'language' '=' <string>
13211321
/// 'defined_in' '=' <string>
1322+
/// 'USR' '=' <string>
13221323
/// 'generated_declaration'
13231324
void Parser::ParseExternalSourceSymbolAttribute(
13241325
IdentifierInfo &ExternalSourceSymbol, SourceLocation Loc,
@@ -1334,13 +1335,16 @@ void Parser::ParseExternalSourceSymbolAttribute(
13341335
Ident_language = PP.getIdentifierInfo("language");
13351336
Ident_defined_in = PP.getIdentifierInfo("defined_in");
13361337
Ident_generated_declaration = PP.getIdentifierInfo("generated_declaration");
1338+
Ident_USR = PP.getIdentifierInfo("USR");
13371339
}
13381340

13391341
ExprResult Language;
13401342
bool HasLanguage = false;
13411343
ExprResult DefinedInExpr;
13421344
bool HasDefinedIn = false;
13431345
IdentifierLoc *GeneratedDeclaration = nullptr;
1346+
ExprResult USR;
1347+
bool HasUSR = false;
13441348

13451349
// Parse the language/defined_in/generated_declaration keywords
13461350
do {
@@ -1362,7 +1366,8 @@ void Parser::ParseExternalSourceSymbolAttribute(
13621366
continue;
13631367
}
13641368

1365-
if (Keyword != Ident_language && Keyword != Ident_defined_in) {
1369+
if (Keyword != Ident_language && Keyword != Ident_defined_in &&
1370+
Keyword != Ident_USR) {
13661371
Diag(Tok, diag::err_external_source_symbol_expected_keyword);
13671372
SkipUntil(tok::r_paren, StopAtSemi);
13681373
return;
@@ -1375,16 +1380,22 @@ void Parser::ParseExternalSourceSymbolAttribute(
13751380
return;
13761381
}
13771382

1378-
bool HadLanguage = HasLanguage, HadDefinedIn = HasDefinedIn;
1383+
bool HadLanguage = HasLanguage, HadDefinedIn = HasDefinedIn,
1384+
HadUSR = HasUSR;
13791385
if (Keyword == Ident_language)
13801386
HasLanguage = true;
1387+
else if (Keyword == Ident_USR)
1388+
HasUSR = true;
13811389
else
13821390
HasDefinedIn = true;
13831391

13841392
if (Tok.isNot(tok::string_literal)) {
13851393
Diag(Tok, diag::err_expected_string_literal)
13861394
<< /*Source='external_source_symbol attribute'*/ 3
1387-
<< /*language | source container*/ (Keyword != Ident_language);
1395+
<< /*language | source container | USR*/ (
1396+
Keyword == Ident_language
1397+
? 0
1398+
: (Keyword == Ident_defined_in ? 1 : 2));
13881399
SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
13891400
continue;
13901401
}
@@ -1396,6 +1407,14 @@ void Parser::ParseExternalSourceSymbolAttribute(
13961407
continue;
13971408
}
13981409
Language = ParseStringLiteralExpression();
1410+
} else if (Keyword == Ident_USR) {
1411+
if (HadUSR) {
1412+
Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause)
1413+
<< Keyword;
1414+
ParseStringLiteralExpression();
1415+
continue;
1416+
}
1417+
USR = ParseStringLiteralExpression();
13991418
} else {
14001419
assert(Keyword == Ident_defined_in && "Invalid clause keyword!");
14011420
if (HadDefinedIn) {
@@ -1414,8 +1433,8 @@ void Parser::ParseExternalSourceSymbolAttribute(
14141433
if (EndLoc)
14151434
*EndLoc = T.getCloseLocation();
14161435

1417-
ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(),
1418-
GeneratedDeclaration};
1436+
ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(), GeneratedDeclaration,
1437+
USR.get()};
14191438
Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()),
14201439
ScopeName, ScopeLoc, Args, std::size(Args), Syntax);
14211440
}

clang/lib/Parse/Parser.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,8 @@ void Parser::Initialize() {
530530
Ident_strict = nullptr;
531531
Ident_replacement = nullptr;
532532

533-
Ident_language = Ident_defined_in = Ident_generated_declaration = nullptr;
533+
Ident_language = Ident_defined_in = Ident_generated_declaration = Ident_USR =
534+
nullptr;
534535

535536
Ident__except = nullptr;
536537

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2842,7 +2842,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
28422842

28432843
static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
28442844
const ParsedAttr &AL) {
2845-
if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 3))
2845+
if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 4))
28462846
return;
28472847

28482848
StringRef Language;
@@ -2852,9 +2852,12 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
28522852
if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1)))
28532853
DefinedIn = SE->getString();
28542854
bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr;
2855+
StringRef USR;
2856+
if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(3)))
2857+
USR = SE->getString();
28552858

28562859
D->addAttr(::new (S.Context) ExternalSourceSymbolAttr(
2857-
S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration));
2860+
S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration, USR));
28582861
}
28592862

28602863
template <class T>

clang/test/AST/ast-dump-attr.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ __attribute__((external_source_symbol(language="Swift", defined_in="module", gen
175175
void TestExternalSourceSymbolAttr2()
176176
__attribute__((external_source_symbol(defined_in="module", language="Swift")));
177177
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr2
178-
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module"{{$}}
178+
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" ""{{$}}
179179

180180
void TestExternalSourceSymbolAttr3()
181181
__attribute__((external_source_symbol(generated_declaration, language="Objective-C++", defined_in="module")));
@@ -192,6 +192,11 @@ __attribute__((external_source_symbol(generated_declaration, defined_in="module"
192192
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr5
193193
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration
194194

195+
void TestExternalSourceSymbolAttr6()
196+
__attribute__((external_source_symbol(generated_declaration, defined_in="module", language="Swift", USR="testUSR")));
197+
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr6
198+
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration "testUSR"
199+
195200
namespace TestNoEscape {
196201
void noescapeFunc(int *p0, __attribute__((noescape)) int *p1) {}
197202
// CHECK: `-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)'

0 commit comments

Comments
 (0)