22
22
#include " clang/AST/DeclTemplate.h"
23
23
#include " clang/AST/ParentMapContext.h"
24
24
#include " clang/AST/Stmt.h"
25
+ #include " clang/Basic/CharInfo.h"
25
26
#include " clang/Basic/LLVM.h"
26
27
#include " clang/Basic/SourceLocation.h"
27
28
#include " clang/Tooling/Syntax/Tokens.h"
28
29
#include " llvm/ADT/None.h"
29
30
#include " llvm/ADT/STLExtras.h"
31
+ #include " llvm/ADT/StringExtras.h"
30
32
#include " llvm/Support/Casting.h"
31
33
#include " llvm/Support/Error.h"
32
34
#include " llvm/Support/FormatVariadic.h"
35
+ #include " llvm/Support/JSON.h"
33
36
#include < algorithm>
34
37
35
38
namespace clang {
@@ -178,8 +181,7 @@ enum class ReasonToReject {
178
181
UnsupportedSymbol,
179
182
AmbiguousSymbol,
180
183
181
- // name validation.
182
- RenameToKeywords,
184
+ // name validation. FIXME: reconcile with InvalidName
183
185
SameName,
184
186
};
185
187
@@ -241,8 +243,6 @@ llvm::Error makeError(ReasonToReject Reason) {
241
243
return " symbol is not a supported kind (e.g. namespace, macro)" ;
242
244
case ReasonToReject::AmbiguousSymbol:
243
245
return " there are multiple symbols at the given location" ;
244
- case ReasonToReject::RenameToKeywords:
245
- return " the chosen name is a keyword" ;
246
246
case ReasonToReject::SameName:
247
247
return " new name is the same as the old name" ;
248
248
}
@@ -437,6 +437,7 @@ struct InvalidName {
437
437
enum Kind {
438
438
Keywords,
439
439
Conflict,
440
+ BadIdentifier,
440
441
};
441
442
Kind K;
442
443
std::string Details;
@@ -447,6 +448,8 @@ std::string toString(InvalidName::Kind K) {
447
448
return " Keywords" ;
448
449
case InvalidName::Conflict:
449
450
return " Conflict" ;
451
+ case InvalidName::BadIdentifier:
452
+ return " BadIdentifier" ;
450
453
}
451
454
llvm_unreachable (" unhandled InvalidName kind" );
452
455
}
@@ -459,12 +462,31 @@ llvm::Error makeError(InvalidName Reason) {
459
462
Reason.Details );
460
463
case InvalidName::Conflict:
461
464
return llvm::formatv (" conflict with the symbol in {0}" , Reason.Details );
465
+ case InvalidName::BadIdentifier:
466
+ return llvm::formatv (" the chosen name \" {0}\" is not a valid identifier" ,
467
+ Reason.Details );
462
468
}
463
469
llvm_unreachable (" unhandled InvalidName kind" );
464
470
};
465
471
return error (" invalid name: {0}" , Message (Reason));
466
472
}
467
473
474
+ static bool mayBeValidIdentifier (llvm::StringRef Ident) {
475
+ assert (llvm::json::isUTF8 (Ident));
476
+ if (Ident.empty ())
477
+ return false ;
478
+ // We don't check all the rules for non-ascii characters (most are allowed).
479
+ bool AllowDollar = true ; // lenient
480
+ if (llvm::isASCII (Ident.front ()) &&
481
+ !isIdentifierHead (Ident.front (), AllowDollar))
482
+ return false ;
483
+ for (char C : Ident) {
484
+ if (llvm::isASCII (C) && !isIdentifierBody (C, AllowDollar))
485
+ return false ;
486
+ }
487
+ return true ;
488
+ }
489
+
468
490
// Check if we can rename the given RenameDecl into NewName.
469
491
// Return details if the rename would produce a conflict.
470
492
llvm::Optional<InvalidName> checkName (const NamedDecl &RenameDecl,
@@ -476,6 +498,8 @@ llvm::Optional<InvalidName> checkName(const NamedDecl &RenameDecl,
476
498
llvm::Optional<InvalidName> Result;
477
499
if (isKeyword (NewName, ASTCtx.getLangOpts ()))
478
500
Result = InvalidName{InvalidName::Keywords, NewName.str ()};
501
+ else if (!mayBeValidIdentifier (NewName))
502
+ Result = InvalidName{InvalidName::BadIdentifier, NewName.str ()};
479
503
else {
480
504
// Name conflict detection.
481
505
// Function conflicts are subtle (overloading), so ignore them.
0 commit comments